在画布上创建线条动画

时间:2018-07-06 03:01:10

标签: javascript animation canvas

我是画布绘制中的新手。我想将PV串模型和电子流向绘制到<canvas>标签中。

这是我要实现的,从以下方向重画线条:

enter image description here

我最初如何设置动画位置,我是否需要通过setTimeout更新它?

这是我到目前为止所尝试的:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

if (canvas.getContext) {
  var ctx = canvas.getContext('2d');
  // drawing code here

  /* First Row */
  ctx.fillStyle = "rgb(2,150,224, 1)";
  ctx.fillRect(50, 50, 50, 50);

  ctx.fillStyle = "rgb(2,150,224, 1)";
  ctx.fillRect(110, 50, 50, 50);

  ctx.fillStyle = "rgb(188,12,50, 1)";
  ctx.fillRect(170, 50, 50, 50);

  ctx.fillStyle = "rgb(2,150,224, 1)";
  ctx.fillRect(230, 50, 50, 50);

  ctx.fillStyle = "rgb(2,150,224, 1)";
  ctx.fillRect(290, 50, 50, 50);

  /* Second Row */
  ctx.fillStyle = "rgb(0,106,160, 1)";
  ctx.fillRect(50, 150, 50, 50);

  ctx.fillStyle = "rgb(0,106,160, 1)";
  ctx.fillRect(110, 150, 50, 50);

  ctx.fillStyle = "rgb(0,106,160, 1)";
  ctx.fillRect(170, 150, 50, 50);

  ctx.fillStyle = "rgb(0,106,160, 1)";
  ctx.fillRect(230, 150, 50, 50);

  ctx.fillStyle = "rgb(0,106,160, 1)";
  ctx.fillRect(290, 150, 50, 50);

  /* Paths */
  ctx.beginPath();
  ctx.lineWidth = "3";
  ctx.strokeStyle = "rgb(34,177,76, 1)";
  ctx.moveTo(0, 75);
  ctx.lineTo(400, 75);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = "10";
  ctx.strokeStyle = "rgb(34,177,76, 1)";
  ctx.moveTo(400, 75);
  ctx.lineTo(400, 175);
  ctx.stroke();

  ctx.beginPath();
  ctx.lineWidth = "3";
  ctx.strokeStyle = "rgb(34,177,76, 1)";
  ctx.moveTo(0, 175);
  ctx.lineTo(400, 175);
  ctx.stroke();


} else {
  // canvas-unsupported code here
}
/* canvas {
  border: 1px solid #d3d3d3;
} */
<canvas id="myCanvas" width="400" height="400">
Your browser does not support the HTML5 canvas tag.</canvas>

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

有很多方法可以对此进行动画处理;这是我的方法(节选;请参见 JSFiddle以获得完整代码):

var lerp = (a, b, t) => a + t * (b - a);
var speed = 0.01;
var time = 0;
var visited = [];
var points = [
  {
    from: { x: 0, y: 75 },
    to: { x: 395, y: 75 }
  },
  {
    from: { x: 395, y: 75 },
    to: { x: 395, y: 175 }
  },
  {
    from: { x: 395, y: 175 },
    to: { x: 0, y: 175 }
  }
];

/* Paths */
ctx.lineWidth = 3;
ctx.strokeStyle = "rgb(34, 177, 76, 1)";

(function update() {
  if (points.length) {
    visited.push({
        x: lerp(points[0].from.x, points[0].to.x, time),
        y: lerp(points[0].from.y, points[0].to.y, time)
    });

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBoxes(ctx);
    ctx.beginPath();
    ctx.moveTo(visited[0].x, visited[0].y)
    visited.forEach(e => ctx.lineTo(e.x, e.y));
    ctx.stroke();

    time += speed;

    if (time >= 1) {
        time = 0;
        points.shift();
    }

    requestAnimationFrame(update);
  }
})();

想法是保留所有转折点的数据结构,然后沿路径lerp,沿路径画一条线。如果您喜欢看起来更“现代”的动画,请使用easing函数而不是lerp;缓动通常更容易实现,并且可能导致某些代码的删除(例如,无需跟踪起点和时间)。

最后一点说明-您的原始代码在画布的右边缘截断了该行,因此我随意使用395而不是400作为绘图宽度。