如何在最大化的canvas元素中适应center-alignPixi.js阶段?

How to fit and center-align Pixi.js stage in the maximized canvas element?

我已经为我的问题准备了完整的jsfiddle -

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

我发现了 Pixi.js 开发人员对 scale the stage 的建议,因此它的 children 会自动缩放,我正在尝试实现它:

$(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>

我上面代码的问题如下-

当您首先 运行 我的代码时,它可以工作。但是在您设置复选框并调整浏览器大小后 window,拖动会中断。

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

$(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

也许 app.stage 可以和我的原始代码一样交互?我认为在那种情况下需要进行一些矩阵计算,这就是为什么数学很难弄清楚的原因。