帆布摆动画 - 画布翻译

时间:2016-04-17 13:25:58

标签: javascript html5 canvas html5-canvas

我试图在HTML5 Canvas中制作简单的钟摆但是我被卡住了。我想将它向左和向右摆动25度,所以我计算我应该在y轴上转换每个帧约-3.5 px(当向右摆动时转换为3.5 px)。我使用下面的代码

var rotation = Math.PI/180, //rotate about 1deg
    translation = -3.5,
    counter = 0; //count rotations

function draw() {
    var element = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    ctx.clearRect(0,0,element.width,element.height);
    ctx.translate(0, translation);
    ctx.rotate(rotation);

    //function draws all objects
    objects(element,ctx);

    if (counter == 25) {
      rotation *= -1;
      translation *= -1;
      counter = -25;
    } 
    counter += 1;

    window.requestAnimationFrame(draw);
  }

一切看起来都不错,但是当钟摆改变方向时,一切都在x轴上平移,几秒后从屏幕上消失。这段代码有什么问题?或许我在计算中遗漏了一些东西?我的代码https://jsfiddle.net/qskxjzv9/2/

提前感谢您的回答。

2 个答案:

答案 0 :(得分:4)

问题在于,当涉及旋转,然后翻译时,x和y将被转换为与看似逻辑不同的方向。

为了解决这个问题,我们实际上不必涉及平移而不是使用它来放置枢轴(旋转点),然后根据计算摆锤运动的不同方式使用绝对旋转。

例如,这将解决翻译问题以及平滑摆动:

  • 更改绘制方法以使用原点(0,0)绘制摆锤 - 它只是改变初始坐标的问题,因此它们围绕(0,0)进展
  • 转换为屏幕的轴心点 - 这是旋转的位置。
  • 使用sin()作为因子旋转 - 这将创建一个平滑的动画,看起来更像是一个摆锤,它将限制移动角度,因为范围是[-1,1]
  • 使用计数器来移动sin() - 这可以作为频率因素(您可以稍后将其转换为实际频率,例如,每分钟钟摆移动n次等)。为了简单起见,我刚刚使用了现有的counter变量并减少了其步长值。

主要代码:

var maxRot = 25 / 180 * Math.PI,    // max 25° in both directions
    counter = 0,

    // these are better off outside loop
    element = document.getElementById('canvas');
    ctx = element.getContext('2d');

function draw() {

  // reset transform using absolute transformation. Include x translation:
  ctx.setTransform(1,0,0,1,element.width*0.5,0);

  // clear screen, compensate for initial translate
  ctx.clearRect(-element.width*0.5,0,element.width,element.height);

  // rotate using sin() with max angle
  ctx.rotate(Math.sin(counter) * maxRot);

  // draw at new orientation which now is pivot point
  objects(element, ctx);

  // move sin() using "frequency"-ish value
  counter += 0.05;

  window.requestAnimationFrame(draw);
}

<强> Fiddle

附加

感谢@ Blindman67提供了额外的改进:

要根据振荡控制频率,您可以做一些小的改动 - 首先定义频率:

var FREQUENCY = 3;

定义一个将进行转换的函数:

function sint(time) {
    return Math.sin(FREQUENCY * time * Math.PI * 0.002); // 0.002 allow time in ms
}

如果您现在更改draw()方法以采用时间参数而不是计数器:

function draw(time) {
   ...
}

然后你可以像这样调用旋转:

ctx.rotate(sint(time) * maxRot);

答案 1 :(得分:1)

您需要将原点转换为您想要旋转的点:

  ctx.translate(element.width / 2, 0);

然后,按照你的建议旋转:

  ctx.rotate(rotation);

最后,翻译回来:

  ctx.translate(- element.width / 2, 0);

请参阅你的小提琴commented fork