在画布上移动形状

时间:2016-03-29 19:17:46

标签: javascript canvas

我想知道在画布中更改形状位置的最佳方法是什么。

以下是我所拥有的:



'use strict';

(function() {

  const canvas = document.getElementsByClassName('canvas')[0],
    c = canvas.getContext('2d');

  //
  c.beginPath();
  c.moveTo(0, 50);
  c.quadraticCurveTo(0, 0, 50, 0);
  c.quadraticCurveTo(100, 0, 100, 50);
  c.quadraticCurveTo(100, 100, 50, 100);
  c.quadraticCurveTo(0, 100, 0, 50);
  c.stroke();

})();

<canvas class="canvas" width="500" height="500"></canvas>
&#13;
&#13;
&#13;

现在,形状位于0,0。如果我想沿X方向移动它,理论上我可以这样做:

c.beginPath();
c.moveTo(x+0,50);
c.quadraticCurveTo(x+0,0,x+50,0);
c.quadraticCurveTo(x+100,0,x+100,50);
c.quadraticCurveTo(x+100,100,x+50,100);
c.quadraticCurveTo(x+0,100,x+0,50);
c.stroke();

实现这一目标的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

当你问 时“我想知道在画布中更改形状位置的最佳方法是什么。”

答案是 使用转换矩阵

使用坐标的直接操作是非常低效的。

2D API提供了一整套用于转换(移动)渲染任何内容的方法。

这些方法是;

  1. ctx.setTransform(axisX_X, axisX_Y, axisY_X, axisY_Y, originX, originY)
  2. ctx.transform(axisX_X, axisX_Y, axisY_X, axisY_Y, originX, originY)
  3. ctx.scale(scaleX, scaleY)
  4. ctx.rotate(radians)
  5. ctx.translate(originX, originY)
  6. (每个链接到MDN)

    除了ctx.putPixelData

    之外,它们会将您呈现的任何内容移动到画布

    因此,通过x和y移动对象,您可以使用

      c.translate(x,y); // move the following coordinates by x, and y;
      c.beginPath();
      c.moveTo(0, 50);
      c.quadraticCurveTo(0, 0, 50, 0);
      c.quadraticCurveTo(100, 0, 100, 50);
      c.quadraticCurveTo(100, 100, 50, 100);
      c.quadraticCurveTo(0, 100, 0, 50);
      c.stroke();
    

    或者直接用

    设置变换
      c.setTransform(1, 0, 0, 1, x, y);
      c.beginPath();
      c.moveTo(0, 50);
      c.quadraticCurveTo(0, 0, 50, 0);
      c.quadraticCurveTo(100, 0, 100, 50);
      c.quadraticCurveTo(100, 100, 50, 100);
      c.quadraticCurveTo(0, 100, 0, 50);
      c.stroke();
    

    如果您不熟悉矩阵操作,这些可能很难理解,因为上面列表中的方法2,3,4,5是现有矩阵的乘法。方法1只是替换现有的矩阵,而不受先前转换的影响。

    这是一个非常简单的函数,它将移动一个对象并包括缩放和旋转。

    // rotation is in radians and rotates the x and y axis
    // scaleX scales along the new xAxis 
    // scaleY scales along the new yAxis
    // x and y translate to the desired screen coordinates
    function position(ctx, x, y, scaleX, scaleY, rotation){
        var scaleRatio = scaleY / scaleX;
        var rx = Math.cos(rotation) * scaleX;
        var ry = Math.sin(rotation) * scaleX;
        ctx.setTransform(rx, ry, -ry * scaleRatio, rx * scaleRatio, x, y);
    }
    

    致电

    position(ctx,100,100,2,0.5, Math.PI/4)
    

    移动在调用100,100像素后绘制的任何内容,使其宽度增加一倍,高一半,并顺时针旋转45度

    恢复为默认值

    position(ctx, 0, 0, 1, 1, 0);
    

    或更快

    ctx.setTransform(1, 0, 0, 1, 0, 0);
    

    有关更详细的说明

    如何使用setTransform以及为什么它优先于其他方法,请参阅this answer

答案 1 :(得分:1)

你有正确的想法。只需确保您在绘制之间清除画布,以确保您不会覆盖画布上当前的内容。然后你可以只更新一些x值,你可以在任何地方绘制它。您可以将此扩展为使用某个y值,以便您也可以垂直移动它。

&#13;
&#13;
'use strict';

(function() {

  const canvas = document.getElementsByClassName('canvas')[0],
        c = canvas.getContext('2d');
  var x = 0;

  function render() {
    c.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
    c.beginPath();
    
    // Adjust path based on x position
    c.moveTo(x, 50);
    c.quadraticCurveTo(x, 0, x + 50, 0);
    c.quadraticCurveTo(x + 100, 0, x + 100, 50);
    c.quadraticCurveTo(x + 100, 100, x + 50, 100);
    c.quadraticCurveTo(x, 100, x, 50);
    c.stroke();
    
    // Doing this for animation
    x += 5;
    if (x > canvas.width) {
      x = -100;
    }
    requestAnimationFrame(render);
  }
  render();
})();
&#13;
<canvas class="canvas" width="500" height="500"></canvas>
&#13;
&#13;
&#13;