javascript - 如何为html5 canvas实现rotate方法

标签 javascript html canvas

我已经使用 javascript 创建了一些形状(看起来像 pacman 的对象),并且我正在使用 Canvas 中内置的矩阵转换为它们制作动画。对象可以在四个方向(左、右、上、下)移动,并且形状基本上会在 Canvas 上来回移动,直到按下另一个按钮。当我使用内置的 Canvas 转换功能时,这些功能可以正常工作;但是,当我尝试实现自己的转换时,发生了一些奇怪的事情。

在正常情况下(当我使用 Canvas 转换时)我首先将 Canvas 原点平移到围绕其旋转的点,围绕这个"new"原点执行旋转,然后将原点平移回它所处的位置之前,在下面的代码中看到:

function renderContent(pm) {
            var t = new Transform();
            context.save();
            context.beginPath();
            context.fillStyle = "Yellow";
            context.strokeStyle = "Yellow";
            context.save();
            var tCopy1 = t;
            context.translate(pm.posX, pm.posY);
            context.rotate(-pm.direction * Math.PI / 180);
            context.translate(-pm.posX, -pm.posY);
            context.arc(pm.posX, pm.posY, pm.size, (pm.startAngle) * Math.PI, (pm.endAngle) * Math.PI);
            context.lineTo(pm.posX, pm.posY);
            context.stroke();
            context.fill();
            var m = t.m;
            t.transform(m);
            context.restore();
            context.restore();
        }

为了实现我自己的转换,我有一个转换类,其功能包括:

function Transform() {
            this.identity();
        }
        Transform.prototype.identity = function () {
            this.m = [1, 0, 0, 1, 0, 0];
        };
        Transform.prototype.rotate = function (rad) {
            var c = Math.cos(rad);
            var s = Math.sin(rad);
            var m11 = this.m[0] * c + this.m[2] * s;
            var m12 = this.m[1] * c + this.m[3] * s;
            var m21 = this.m[0] * -s + this.m[2] * c;
            var m22 = this.m[1] * -s + this.m[3] * c;
            this.m[0] = m11;
            this.m[1] = m12;
            this.m[2] = m21;
            this.m[3] = m22;
        };
        Transform.prototype.translate = function (x, y) {
            this.m[4] += this.m[0] * x + this.m[2] * y;
            this.m[5] += this.m[1] * x + this.m[3] * y;
        };

        Transform.prototype.scale = function (sx, sy) {
            this.m[0] *= sx;
            this.m[1] *= sx;
            this.m[2] *= sy;
            this.m[3] *= sy;
        };

在 renderContext() 函数中,我对 translate() 和 rotate() 使用了本质上相同的函数调用(这使得 pacman 对象在碰到 Canvas 边界时可以转身)但是出于某种原因,在我的实现中,物体不会转动(180 度)。

对于我的转换,我基本上实例化了一个转换对象,调用对象上的转换操作,制作转换矩阵的副本,然后使用转换的结果矩阵设置 Canvas : 例如:

var t = new Transform();
var tCopy1 = t;
tCopy1.translate(pm.posX, pm.posY);
t.rotate(-pm.direction * Math.PI / 180);
t.translate(-pm.posX, -pm.posY);
...
var m = t.m;
t.transform(m);

这可能需要看很多代码,但是实现旋转矩阵变换的正确方法是什么(因为 canvas.rotate() 正在工作)?

最佳答案

这是吃 bean 顺时针旋转方向 Angular 。

更新

现在以紫色显示转换错误。旋转看起来正确,但平移已关闭。

更新 2

我认为我之前的测试很糟糕。转换看起来不错,只是对 to_radians 进行了一些小的调整。新测试显示上下文转换/旋转,后跟 Transform 类。

var can = document.getElementById('can');
var context = can.getContext('2d');
var to_rad = Math.PI / 180; // to radians

function main() {
  context.fillStyle="black";
  context.fillRect(0, 0, can.width, can.height);

  var pm = {
    direction: 0,
    posX: 50,
    posY: 100,
    size: 20,
    startAngle: 45,
    endAngle: 315
  };

  var i = 0;
  
  function loopTest() {
    pm.direction = i * 90;
    pm.posX = 50 * (i+1);
    renderContent(pm);
    setTimeout(function(){
      renderContent2(pm);
    }, 1000);
    i++;
    if (i < 4) {
      setTimeout(loopTest, 2000);
    }
  }

  loopTest();



}

function renderContent(pm) {
  context.save();
  context.beginPath();
  context.fillStyle = "Yellow";
  context.strokeStyle = "Yellow";
  
  context.translate(pm.posX, pm.posY);
  context.rotate(pm.direction * to_rad);
  context.translate(-pm.posX, -pm.posY);
  context.arc(pm.posX, pm.posY, pm.size, pm.startAngle * to_rad, pm.endAngle * to_rad);
  context.lineTo(pm.posX, pm.posY);
  context.stroke();
  context.fill();

  context.fillStyle="red";
  context.font="16px Arial";
  context.textAlign="center";
  context.fillText(pm.direction, pm.posX,pm.posY+pm.size);
  context.restore();
}



function renderContent2(pm) {
  var t = new Transform();
  context.save();
  context.beginPath();
  context.fillStyle = "#990099";
  context.strokeStyle = "#990099";
  t.translate(pm.posX, pm.posY);
  t.rotate(pm.direction * to_rad);
  t.translate(-pm.posX, -pm.posY);
  context.transform.apply(context, t.m);
  context.arc(pm.posX, pm.posY, pm.size, pm.startAngle * to_rad, pm.endAngle * to_rad);
  context.lineTo(pm.posX, pm.posY);
  context.stroke();
  context.fill();
  context.fillStyle="White";
  context.font="16px Arial";
  context.textAlign="center";
  context.fillText(pm.direction, pm.posX,pm.posY+pm.size);
  context.restore();
}


function Transform() {
  this.identity();
}
Transform.prototype.identity = function () {
  this.m = [1, 0, 0, 1, 0, 0];
};
Transform.prototype.rotate = function (rad) {
  var c = Math.cos(rad);
  var s = Math.sin(rad);
  var m11 = this.m[0] * c + this.m[2] * s;
  var m12 = this.m[1] * c + this.m[3] * s;
  var m21 = this.m[0] * -s + this.m[2] * c;
  var m22 = this.m[1] * -s + this.m[3] * c;
  this.m[0] = m11;
  this.m[1] = m12;
  this.m[2] = m21;
  this.m[3] = m22;
};
Transform.prototype.translate = function (x, y) {
  this.m[4] += this.m[0] * x + this.m[2] * y;
  this.m[5] += this.m[1] * x + this.m[3] * y;
};

Transform.prototype.scale = function (sx, sy) {
  this.m[0] *= sx;
  this.m[1] *= sx;
  this.m[2] *= sy;
  this.m[3] *= sy;
};


main();
canvas {
  border:3px solid red;
}
<canvas id="can" width="300" height="200"></canvas>

关于javascript - 如何为html5 canvas实现rotate方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33131861/

相关文章:

javascript - 两个 jQuery 事件处理程序的内容在功能上应该是等效的,但表现出不同的行为

javascript - 如何对一组数字求和,使数组的总和为 100

javascript - 性能警告Processing.js

javascript - 将javascript添加到wordpress页面

html - 手动设置高度时div重叠

javascript - Jquery Canvas 绘制不一致的形状

javascript - "canvas.toDataURL("图像/png ")"在 Firefox 中无法正常工作

javascript - 无法从 miithril View 启动灯箱

javascript - Angular 空选项删除

javascript - 显示 : None/Block Style Tab Menu Creation with Buttons and Javascript