【问题标题】:How to implement rotate method for html5 canvas如何实现html5画布的旋转方法
【发布时间】:2016-01-12 22:14:59
【问题描述】:

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

在正常情况下(当我使用画布转换时),我首先将画布原点平移到正在旋转的点,围绕这个“新”原点执行旋转,然后将原点转换回原点是之前的,见于以下代码:

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 对象在碰到画布边界时可以转身)但出于某种原因,在我的实现中,物体不会转身(180 度)。

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

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() 正在工作)?

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    这是 pacman 围绕方向角顺时针旋转。

    更新

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

    更新 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;
    }
    &lt;canvas id="can" width="300" height="200"&gt;&lt;/canvas&gt;

    【讨论】:

    • 提问者有本地画布 (context.rotate) 版本工作。我相信他们在问为什么他们自己的转换矩阵版本不起作用。我可能是错的,因为我现在莫名其妙地昏昏欲睡。 :-z
    • 啊,是的,你是正确的@markE。我会看看他的变换。
    • @markE 我使用context.transform.apply(context, t.m) 将数组作为参数应用,它似乎工作得很好。
    猜你喜欢
    • 2012-01-21
    • 2015-05-25
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多