canvas动画

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      html {
        background: #333;
      }
    </style>
  </head>
  <body>
    <!-- 
      canvas动画
      特点:
        1. 把之前的画布清空
        2. 更新位置,重新画一遍
    -->
    <canvas></canvas>
    <script>
      // 获取画布元素
      const cvs = document.querySelector('canvas');
      // 获取canvas绘制上下文
      const ctx = cvs.getContext('2d');

      // 初始化画布
      function init() {
      	// 更正分辨率
        cvs.width = window.innerWidth * devicePixelRatio;
        cvs.height = window.innerHeight * devicePixelRatio;
      }
      init();

      /**
       * 获取min到max之间的随机数
       * @param {Number} min
       * @param {Number} max
       * @return {Number}
       * **/
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min) + min);
      }

      // 创建一个画点的类
      class Point {
        constructor() {
          this.r = 6;
          this.x = getRandom(0, cvs.width - this.r / 2);
          this.y = getRandom(0, cvs.height - this.r / 2);
          // 给小点添加速度
          this.xSpeed = getRandom(-500, 500);
          this.ySpeed = getRandom(-500, 500);
          // 记录上一次画的时间,通过时间和速度计算出移动的距离
          this.lastDrawTime = null;
        }

        // 画点
        draw() {
          if (this.lastDrawTime) {
            // 计算新的坐标
            const duration = Date.now() - this.lastDrawTime;
            let x = this.x + (this.xSpeed * duration) / 1000;
            let y = this.y + (this.ySpeed * duration) / 1000;

            // 考虑边界条件
            if (x > cvs.width - this.r / 2) {
              this.x = cvs.width - this.r / 2;
              this.xSpeed = -this.xSpeed;
            } else if (x < 0) {
              this.x = 0;
              this.xSpeed = -this.xSpeed;
            }

            if (y > cvs.height - this.r / 2) {
              this.y = cvs.height - this.r / 2;
              this.ySpeed = -this.ySpeed;
            } else if (y < 0) {
              this.y = 0;
              this.ySpeed = -this.ySpeed;
            }

            this.x = x;
            this.y = y;
          }

          ctx.beginPath();
          ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
          ctx.fillStyle = 'rgb(200,200,200)';
          ctx.fill();

          this.lastDrawTime = Date.now();
        }
      }

      // 创建画图的类
      class Graph {
        // 点与点之间随着距离的增大,连线的透明度逐渐降低,超过最大距离则透明度为0
        constructor(pointNum = 30, maxDis = 500) {
          this.points = new Array(pointNum).fill(0).map(() => new Point());
          this.maxDis = maxDis;
        }

        draw() {
          // 递归调用,不断的清空画布,重新画
          requestAnimationFrame(() => {
            this.draw();
          });

          // 每次画之前先清空画布
          ctx.clearRect(0, 0, cvs.width, cvs.height);

          for (let i = 0; i < this.points.length; i++) {
            const p1 = this.points[i];
            p1.draw();
            // 与别的点进行连线
            for (let j = i + 1; j < this.points.length; j++) {
              const p2 = this.points[j];
              const d = Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
              if (d > this.maxDis) {
                continue;
              }
              ctx.beginPath();
              ctx.moveTo(p1.x, p1.y);
              ctx.lineTo(p2.x, p2.y);
              ctx.closePath();
              ctx.strokeStyle = `rgba(200,200,200,${1 - d / this.maxDis})`;
              ctx.stroke();
            }
          }
        }
      }

      const g = new Graph();
      g.draw();
    </script>
  </body>
</html>

requestAnimationFrame特点

  1. 性能高效:他能根据浏览器的刷新频率自动调整动画的帧率,使得动画可以在不同设备上都能以最佳性能运行
  2. 平滑动画:会在浏览器下一次重绘之前执行动画
  3. 页面失去焦点时,停止动画运行,获取焦点后继续执行动画
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值