代码之家  ›  专栏  ›  技术社区  ›  Alexander Farber

如何在最大化的画布元素中缩放Pixi.js舞台并使其居中?

  •  0
  • Alexander Farber  · 技术社区  · 4 年前

    我已经准备了一份完整的 jsfiddle 对于我的问题-

    screenshot

    对于棋盘游戏,我试图在两侧使用jQuery UI按钮,并将屏幕的其余部分分配给Pixi绘图区域。

    我找到了Pixi.js开发人员的建议 scale the stage ,这样它的子项就会自动缩放,下面我正在尝试实现它:

    $(function() {
      var WIDTH = 400;
      var HEIGHT = 400;
      var RATIO = WIDTH / HEIGHT;
    
      var scaleX = 1,
        scaleY = 1,
        offsetX = 0,
        offsetY = 0,
        oldX, oldY;
    
      var app = new PIXI.Application({
        width: WIDTH,
        height: HEIGHT,
        view: document.getElementById('pixiCanvas'),
        backgroundColor: 0xFFFFFF
      });
    
      app.stage.interactive = true;
      app.stage.on('pointerdown', onDragStart)
        .on('pointerup', onDragEnd)
        .on('pointerupoutside', onDragEnd)
        .on('pointermove', onDragMove);
    
      var background = new PIXI.Graphics();
      for (var i = 0; i < 8; i++) {
        for (var j = 0; j < 8; j++) {
          if ((i + j) % 2 == 0) {
            background.beginFill(0xCCCCFF);
            background.drawRect(i * WIDTH / 8, j * HEIGHT / 8, WIDTH / 8, HEIGHT / 8);
            background.endFill();
          }
        }
      }
      app.stage.addChild(background);
    
      var bunny = PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png');
      bunny.anchor.set(0.5);
      bunny.scale.set(2);
      bunny.x = WIDTH / 2;
      bunny.y = HEIGHT / 2;
      app.stage.addChild(bunny);
    
      function onDragStart(ev) {
        var stagePoint = ev.data.getLocalPosition(app.stage);
        if (bunny.getBounds().contains(stagePoint.x, stagePoint.y)) {
          bunny.alpha = 0.5;
          oldX = stagePoint.x;
          oldY = stagePoint.y;
          this.data = ev.data;
        }
      }
    
      function onDragMove() {
        if (this.data) {
          var stagePoint = this.data.getLocalPosition(app.stage);
          bunny.x += stagePoint.x - oldX;
          bunny.y += stagePoint.y - oldY;
          oldX = stagePoint.x;
          oldY = stagePoint.y;
        }
      }
    
      function onDragEnd() {
        if (this.data) {
          bunny.alpha = 1;
          var stagePoint = this.data.getLocalPosition(app.stage);
          this.data = null;
        }
      }
    
      $(':button').button();
      $('#scaleCheck').checkboxradio();
    
      window.onresize = function() {
        if (!$('#scaleCheck').prop('checked')) {
          return;
        }
    
        var canvasRatio = $('#pixiCanvas').width() / $('#pixiCanvas').height();
    
        if (canvasRatio > RATIO) {               // if canvas is too wide
          scaleX  = 1 / canvasRatio;
          scaleY  = 1;
          offsetX = 0;
          offsetY = 0;
        } else {
          scaleX  = 1;
          scaleY  = canvasRatio;
          offsetX = 0;
          offsetY = 0;
        }
    
        app.stage.scale.set(scaleX, scaleY);
        app.stage.position.set(offsetX, offsetY); // how to center-align?
      }
    
      window.onresize();
    });
    body {
      margin: 0;
      padding: 0;
    }
    
    #mainDiv {
      width: 100%;
      height: 100vh;
      background: #FFF;
      display: flex;
    }
    
    #leftMenuDiv {
      text-align: center;
      background: #FCC;
    }
    
    #rightMenuDiv {
      text-align: center;
      background: #CFC;
      flex-shrink: 1;
    }
    
    #canvasDiv {
      flex-grow: 1;
    }
    
    #pixiCanvas {
      width: 100%;
      height: 100%;
      background: #CCF;
      box-sizing: border-box;
      border: 4px red dotted;
    }
    <div id="mainDiv">
      <div id="leftMenuDiv">
        <button id="btn1">Button 1</button><br>
        <button id="btn2">Button 2</button><br>
        <button id="btn3">Button 3</button><br>
      </div>
    
      <div id="canvasDiv">
        <canvas id="pixiCanvas"></canvas>
      </div>
    
      <div id="rightMenuDiv">
        <input id="scaleCheck" type="checkbox">
        <label for="scaleCheck">Fit and center Pixi stage</label><br>
        <button id="btn4">Button 4</button><br>
        <button id="btn5">Button 5</button><br>
        <button id="btn6">Button 6</button><br>
      </div>
    </div>
    
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
    <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <script src="//cdn.jsdelivr.net/npm/pixi.js@5.3.3/dist/pixi.min.js"></script>

    我对上述代码的问题如下-

    当你第一次运行我的代码时,它就工作了。但是,在您设置复选框并调整浏览器窗口大小后,拖动将中断。

    0 回复  |  直到 4 年前
        1
  •  0
  •   Alexander Farber    4 年前

    我已经能够通过以下代码解决我的问题:

    screenshot

    $(function() {
        var WIDTH = 400;
        var HEIGHT = 400;
        var RATIO = WIDTH / HEIGHT;
    
        var scaleX = 1, scaleY = 1, offsetX = 0, offsetY = 0;
    
        var app = new PIXI.Application({
            width: WIDTH,
            height: HEIGHT,
            view: document.getElementById('pixiCanvas'),
            backgroundColor: 0xFFFFFF
        });
    
        var background = new PIXI.Graphics();
        for (var i = 0; i < 8; i++) {
            for (var j = 0; j < 8; j++) {
                if ((i + j) % 2 == 0) {
                    background.beginFill(0xCCCCFF);
                    background.drawRect(i * WIDTH / 8, j * HEIGHT / 8, WIDTH / 8, HEIGHT / 8);
                    background.endFill();
                }
            }
        }
        app.stage.addChild(background);
    
        var bunny = PIXI.Sprite.from('https://pixijs.io/examples/examples/assets/bunny.png');
        bunny.interactive = true;
        bunny.buttonMode = true;
        bunny.anchor.set(0.5);
        bunny.scale.set(2);
        bunny.x = WIDTH / 2;
        bunny.y = HEIGHT / 2;
        bunny.on('pointerdown', onDragStart)
             .on('pointerup', onDragEnd)
             .on('pointerupoutside', onDragEnd)
             .on('pointermove', onDragMove);
        app.stage.addChild(bunny);
    
        function onDragStart(ev) {
            this.data = ev.data;
            this.alpha = 0.5;
        }
    
        function onDragMove() {
            if (this.data) {
                var newPos = this.data.getLocalPosition(this.parent);
                this.x = newPos.x;
                this.y = newPos.y;
            }
        }
    
        function onDragEnd() {
            if (this.data) {
                this.alpha = 1;
                this.data = null;
            }
        }
    
        $(':button').button();
        $('#scaleCheck').checkboxradio();
    
        window.onresize = function() {
            if (!$('#scaleCheck').prop('checked')) {
                return;
            }
    
            var canvasRatio = $('#pixiCanvas').width() / $('#pixiCanvas').height();
            
            if (canvasRatio > RATIO) {          // if canvas is too wide
                scaleX = RATIO / canvasRatio;
                scaleY = 1;
                offsetX = (1 - scaleX) * WIDTH / 2;
                offsetY = 0;
            } else {
                scaleX = 1;
                scaleY = canvasRatio / RATIO;
                offsetX = 0;
                offsetY = (1 - scaleY) * HEIGHT / 2;
            }
    
            app.stage.scale.set(scaleX, scaleY);
            app.stage.position.set(offsetX, offsetY);
        }
    
        window.onresize();
    });
    body {
        margin: 0;
        padding: 0;
    }
    
    #mainDiv {
        width: 100%;
        height: 100vh;
        background: #FFF;
        display: flex;
    }
    
    #leftMenuDiv {
        text-align: center;
        background: #FCC;
    }
    
    #rightMenuDiv {
        text-align: center;
        background: #CFC;
        flex-shrink: 1;
    }
    
    #canvasDiv {
        flex-grow: 1;
    }
    
    #pixiCanvas {
        width: 100%;
        height: 100%;
        background: #CCF;
        box-sizing: border-box;
        border: 4px red dotted;
    }
    <div id="mainDiv">
      <div id="leftMenuDiv">
        <button id="btn1">Button 1</button><br>
        <button id="btn2">Button 2</button><br>
        <button id="btn3">Button 3</button><br>
      </div>
    
      <div id="canvasDiv">
        <canvas id="pixiCanvas"></canvas>
      </div>
    
      <div id="rightMenuDiv">
        <input id="scaleCheck" type="checkbox" checked>
        <label for="scaleCheck">Fit and center Pixi stage</label><br>
        <button id="btn4">Button 4</button><br>
        <button id="btn5">Button 5</button><br>
        <button id="btn6">Button 6</button><br>
      </div>
    </div>
    
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
    <script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    <script src="//cdn.jsdelivr.net/npm/pixi.js@5.3.3/dist/pixi.min.js"></script>

    对我来说,主要的变化是使可拖动的精灵具有交互性,并为其添加拖动监听器,而不是 app.stage .

    也许 吧 应用程序阶段 可以像在我的原始代码中一样具有交互性吗?我认为在这种情况下需要一些矩阵计算,这就是为什么数学很难弄清楚。