HTML画布和动画

gue*_*tli 2 javascript animation html5-canvas

我知道如何用lineTo()画一条线:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(300, 150);
ctx.stroke(); 
Run Code Online (Sandbox Code Playgroud)

有没有办法将动画(例如anime.js)应用于行?

Bli*_*n67 10

一次一帧

要进行动画制作,您需要以略高于人眼可以看到的不同帧(每秒约20帧)的速度稍微不同地绘制图形。

为此,您需要先清除显示,然后绘制场景。

例如,让一条线动画为围绕画布中心以两个圆圈移动的点之间的线。变量time用于确定画线的位置。如果我们添加到time线中,则动画是向前动画,如果从时间中减去,则线向相反方向移动。可变时间的变化越大,线移动得越快。

 // time determines where the line is drawn
 function drawLine(time) {
     // get size of the canvas
     const w = ctx.canvas.width;
     const h = ctx.canvas.height;

     // get the radius of circle that fits canvas
     const radius = Math.min(w, h) / 2;

     // get the center of the canvas
     const cx = w / 2;
     const cy = h / 2;

     // start of line outer radius
     const x1 = Math.cos(time) * radius * 0.9;
     const y1 = Math.sin(time) * radius * 0.9;

     // end of line, offset time 
     const x2 = Math.cos(time * 0.707) * radius * 0.4;
     const y2 = Math.sin(time * 0.707) * radius * 0.4;

     ctx.moveTo(x1 + cx, y1 + cy); // Add to path
     ctx.lineTo(x2 + cx, y2 + cy);

 }
Run Code Online (Sandbox Code Playgroud)

渲染功能

现在您有了一个可以在不同时间画一条线的函数,您需要以看起来像动画的速率重复该线。通过DOM的现代浏览器提供了一个回调函数,该回调函数旨在通过DOM呈现动画内容。每秒调用60次(按请求,每个请求),这是DOM呈现动画内容的最快速度。要设置回调函数,请使用requestAnimationFrame(请参见示例)

我们通常使用一个更新功能来处理清除和绘制框架的整个过程。下面是一个更新函数的示例,该函数对上面的line函数进行动画处理。

  var time = 0;      // position of line as abstracted time
  const rate = 0.01; // Movement per frame in radians
  requestAnimationFrame(updateFrame); // request the first frame

  function updateFrame() {
       ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // clear the canvas
       time += rate;
       // set the line with color and end cap
       ctx.lineWidth = 10;
       ctx.lineCap = "round";
       ctx.strokeStyle = "black";


       // create a path
       ctx.beginPath();
       drawLine(time);

       // now draw it
       ctx.stroke();  
       requestAnimationFrame(updateFrame);
  }
Run Code Online (Sandbox Code Playgroud)

运行示例

综上所述,我们得到以下内容。

我添加了一些东西使其变得更有趣。单击画布以添加行并重新启动时间变量。添加线条可以感觉到在设备无法以愚蠢的速度绘制线条之前可以绘制多少条线条。对于普通设备,将有很多行。(有很多方法可以大大提高该速度,但这要先进一些)

添加很多行还将显示一些有趣的别名FX,它们可以创建不存在的运动模式,但是这是由于DOM如何渲染到画布以及眼睛如何推断运动的微小缺陷所致。

还检查与页面相比的画布大小,并根据需要调整画布的大小。最好使用这种方式调整大小,而不是使用调整大小事件,因为调整大小事件与显示不同步。

 // time determines where the line is drawn
 function drawLine(time) {
     // get size of the canvas
     const w = ctx.canvas.width;
     const h = ctx.canvas.height;

     // get the radius of circle that fits canvas
     const radius = Math.min(w, h) / 2;

     // get the center of the canvas
     const cx = w / 2;
     const cy = h / 2;

     // start of line outer radius
     const x1 = Math.cos(time) * radius * 0.9;
     const y1 = Math.sin(time) * radius * 0.9;

     // end of line, offset time 
     const x2 = Math.cos(time * 0.707) * radius * 0.4;
     const y2 = Math.sin(time * 0.707) * radius * 0.4;

     ctx.moveTo(x1 + cx, y1 + cy); // Add to path
     ctx.lineTo(x2 + cx, y2 + cy);

 }
Run Code Online (Sandbox Code Playgroud)
  var time = 0;      // position of line as abstracted time
  const rate = 0.01; // Movement per frame in radians
  requestAnimationFrame(updateFrame); // request the first frame

  function updateFrame() {
       ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // clear the canvas
       time += rate;
       // set the line with color and end cap
       ctx.lineWidth = 10;
       ctx.lineCap = "round";
       ctx.strokeStyle = "black";


       // create a path
       ctx.beginPath();
       drawLine(time);

       // now draw it
       ctx.stroke();  
       requestAnimationFrame(updateFrame);
  }
Run Code Online (Sandbox Code Playgroud)
// time determines where the line is drawn
function drawLine(time) {
  // get size of the canvas
  const w = ctx.canvas.width;
  const h = ctx.canvas.height;

  // get the radius of circle that fits canvas
  const radius = Math.min(w, h) / 2;

  // get the center of the canvas
  const cx = w / 2;
  const cy = h / 2;

  // start of line outer radius
  const x1 = Math.cos(time) * radius * 0.95;
  const y1 = Math.sin(time*1.04) * radius * 0.95;

  // end of line, offset time 
  const x2 = Math.cos(time * 0.9) * radius * 0.82;
  const y2 = Math.sin(time * 0.902) * radius * 0.82;

  // Offset inner circle  a little for interesting FX

  const ox = Math.cos(time * 0.7) * radius * 0.12;
  const oy = Math.sin(time * 0.703) * radius * 0.12;


  ctx.moveTo(x1 + cx, y1 + cy);
  ctx.lineTo(x2 + cx + ox, y2 + cy + oy);

}
const ctx = canvas.getContext("2d");

canvas.addEventListener("click",() => {
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    timeOffsets.push(timeOffsets[timeOffsets.length -1] * 1.002);
    time = 2;
});
const timeOffsets = [1];
var time = 0; // position of line as abstracted time
const rate = 0.01; // Movement per frame in radians
requestAnimationFrame(updateFrame); // request the first frame

function updateFrame() {
  // check if the canvas size needs to change to fit the page
  if (innerWidth !== ctx.canvas.width || innerHeight !== ctx.canvas.height) {
    // changing the canvas resolution also clears the canvas so dont need to clear
    ctx.canvas.width = innerWidth;
    ctx.canvas.height = innerHeight;
    timeOffsets.length = 1;
  } else {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // clear the canvas
  }
  time += rate;
  var separate = 0;
  const angularSep = 8 / Math.min(ctx.canvas.width, ctx.canvas.height);
  // set the line with color and end cap
  ctx.lineWidth = 2;
  ctx.lineCap = "round";
  ctx.strokeStyle = "black";
  ctx.beginPath();

  for(const t of timeOffsets) {
      drawLine(time * t + separate);
      separate += angularSep;
  }

  ctx.stroke();
  requestAnimationFrame(updateFrame);
}
Run Code Online (Sandbox Code Playgroud)