可视化系列讲解:canvas的动画实现

文章目录

  • 一、Canvas动画
      • 1.1 Canvas绘图都是通过JavaScript 去操控的,如要实现一些交互性动画是相当容易的。那Canvas是如何做一些基本动画的?
      • 1.2 Canvas 画出一帧动画的基本步骤(如要画出流畅动画,1s 需绘60帧):
  • 二、Canvas-绘制秒针-setInterval实现
      • 2.1 setTimout定时器的缺陷
  • 三、Canvas-绘制秒针--requestAnimationFrame实现
      • 3.1 requestAnimationFrame函数
  • 四、其他动画案例


一、Canvas动画

1.1 Canvas绘图都是通过JavaScript 去操控的,如要实现一些交互性动画是相当容易的。那Canvas是如何做一些基本动画的?

◼ canvas可能最大的限制就是图像一旦绘制出来,它就是一直保持那样了。
◼ 如需要执行动画,不得不对画布上所有图形进行一帧一帧的重绘(比如在1秒绘60帧就可绘出流畅的动画了)。
◼ 为了实现动画,我们需要一些可以定时执行重绘的方法。然而在Canvas中有三种方法可以实现:分别为 setInterval 、 setTimeout 和 requestAnimationFrame 三种方法来定期执行指定函数进行重绘。

1.2 Canvas 画出一帧动画的基本步骤(如要画出流畅动画,1s 需绘60帧):

◼ 第一步:用 clearRect 方法清空 canvas ,除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。
◼ 第二步:保存 canvas 状态,如果加了 canvas 状态的设置(样式,变形之类的),又想在每画一帧之时都是原始状态的话,
你需要先保存一下。
◼ 第三步:绘制动画图形(animated shapes) ,即绘制动画中的一帧。
◼ 第四步:恢复 canvas 状态,如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。

二、Canvas-绘制秒针-setInterval实现

2.1 setTimout定时器的缺陷

setTimeout定时器不是非常精准的,因为setTimeout的回调函数是放到了宏任务中等待执行。
◼ 如果微任务中一直有未处理完成的任务,那么setTimeout的回调函数就有可能不会在指定时间内触发回调
◼ 如果想要更加平稳和更加精准的定时执行某个任务的话,可以使用requestAnimationFrame函数。

可视化系列讲解:canvas的动画实现_第1张图片

<!DOCTYPE html>
<html lang="zh-CH">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    * {
      margin: 0;
      padding: 0;
    }
    body {
      padding: 100px;
      margin: auto;
      background-image: url(../images/grid.png);
    }
    canvas {
      background-color: rgba(255, 0, 0, 0.1);
    }
  </style>
</head>
<body>
  
  <!-- 如果不给宽高 默认宽300px 高150px -->
  <canvas id="box" width="300" height="300">
    您的浏览器不兼容Canvas,请升级浏览器
  </canvas>

  <script>
    // 这个函数就是动画的一帧
    function draw(ctx, count) {
      // 清空画布
      ctx.clearRect(0, 0, 300, 300)
      ctx.save()
      // 绘图
      ctx.translate(100, 100)
      // Math.PI * 2 圆
      // Math.PI * 2 / 60 把圆分为60份
      ctx.rotate(Math.PI * 2 / 60 * count)
      ctx.lineWidth = 6
      ctx.lineCap = 'round'
      ctx.strokeStyle = 'green'
      ctx.beginPath()
      ctx.moveTo(0, 0)
      ctx.lineTo(0, -80)
      ctx.stroke()
      ctx.restore()
    }
    window.onload = function() {
      const canvasEl = document.getElementById('box')
      if (!canvasEl.getContext) return
      let ctx = canvasEl.getContext('2d')
      let count = 0
      draw(ctx, count)

      setInterval(() => {
        count++
        if (count >= 60) {
          count = 0
        }
        draw(ctx, count)
      }, 1000);
    }
  </script>
</body>
</html>

三、Canvas-绘制秒针–requestAnimationFrame实现

3.1 requestAnimationFrame函数

告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用该函数的回调函数来更新动画。
◼ 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
◼ 若想在浏览器下次重绘之前继续更新下一帧动画,那么在回调函数自身内必须再次调用 requestAnimationFrame()
◼ 通常每秒钟回调函数执行 60 次左右,也有可能会被降低。

<!DOCTYPE html>
<html lang="zh-CH">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <style>
    * {
      margin: 0;
      padding: 0;
    }
    body {
      padding: 100px;
      margin: auto;
      background-image: url(../images/grid.png);
    }
    canvas {
      background-color: rgba(255, 0, 0, 0.1);
    }
  </style>
</head>
<body>
  
  <!-- 如果不给宽高 默认宽300px 高150px -->
  <canvas id="box" width="300" height="300">
    您的浏览器不兼容Canvas,请升级浏览器
  </canvas>

  <script>
    // 这个函数就是动画的一帧
    function draw(ctx) {
      let second = new Date().getSeconds()
      ctx.clearRect(0, 0, 300, 300)
      ctx.save()
      ctx.translate(100, 100)
      ctx.rotate(Math.PI * 2 / 60 * second)
      ctx.lineWidth = 6
      ctx.lineCap = 'round'
      ctx.strokeStyle = 'green'
      ctx.beginPath()
      ctx.moveTo(0, 0)
      ctx.lineTo(0, -80)
      ctx.stroke()
      ctx.restore()
    
      requestAnimationFrame(() => {
        draw(ctx)
      })
    }

    window.onload = function() {
      const canvasEl = document.getElementById('box')
      if (!canvasEl.getContext) return
      let ctx = canvasEl.getContext('2d')
      requestAnimationFrame(() => {
        draw(ctx)
      })
    }
  </script>
</body>
</html>

四、其他动画案例

案列地址

你可能感兴趣的:(svg,css,canvas,动画,css3,javascript)