如何在最大化的canvas元素中使Pixi.js舞台适合和居中对齐?

如何解决如何在最大化的canvas元素中使Pixi.js舞台适合和居中对齐?

我已经为问题准备了完整的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>

我与上面的代码有关的问题如下-

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

解决方法

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-