canvas实现动画粒子背景(记录)

212 阅读1分钟

1.编写样式

  * {
        margin: 0;
        padding: 0;
      }
      canvas {
        background: #000;
        display: block;
        pointer-events: none;
      }

2.编写html标签内容

    <canvas></canvas>

3.编写JavaScript内容

第一步:创建窗口重载函数让窗口变化时重新设置canvas的大小

// 设置canvas的大小
const setCanvasSize = () => {
    const window_width = window.innerWidth;
    const window_height = window.innerHeight;
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
};
// 窗口变化时重载canvas大小
window.onresize = function () {
    setCanvasSize();
};


// 获取canvas元素
const canvas = document.querySelector("canvas");

//   设置大小
setCanvasSize();

获取min到max之间的随机数

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

生成点的构造函数

//   生成点的构造函数
class Point {
    constructor() {
      this.radius = 2;
      this.x = getRandomNum(0, canvas.width - this.radius / 2);
      this.y = getRandomNum(0, canvas.height - this.radius / 2);
      this.xSpeed = getRandomNum(-50, 50);
      this.ySpeed = getRandomNum(-50, 50);
      this.lastDrawTime = null;
    }
    // 画点的方法
    drawPoint() {
    // 判断是否是第一次画点
      if (this.lastDrawTime) {
        const duration = (Date.now() - this.lastDrawTime) / 1000;
        // 算出距离
        const xDis = this.xSpeed * duration,
          yDis = this.ySpeed * duration;
        //   算出新的坐标
        let x = this.x + xDis,
          y = this.y + yDis;
        //   判断坐标是否超出边界
        if (x > canvas.width - this.radius / 2) {
          x = canvas.width - this.radius / 2;
          this.xSpeed = -this.xSpeed;
        } else if (x < 0) {
          x = 0;
          this.xSpeed = -this.xSpeed;
        }
        if (y > canvas.height - this.radius / 2) {
          y = canvas.height - this.radius / 2;
          this.ySpeed = -this.ySpeed;
        } else if (y < 0) {
          y = 0;
          this.ySpeed = -this.ySpeed;
        }
        // 设置更新坐标位置
        this.x = x;
        this.y = y;
      }
      // 绘画点
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      ctx.fillStyle = "#fff";
      ctx.fill();
      this.lastDrawTime = Date.now();
    }
}
// 构造多个点的类
class GraphLinePoint {
    constructor(number = 20, maxDis = 200) {
        this.points = new Array(number).fill(0).map(() => new Point());
        this.maxDis = maxDis;
    }
    // 连线
    drawLinePoint() {
        // 循环动画产生的函数 (类似于setTimeout等定时器,requestAnimationFrame是新API)
        requestAnimationFrame(() => {
            this.drawLinePoint();
        });
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        // 循环产生的点
        for (let i = 0; i < this.points.length; i++) {
            const pl = this.points[i];
            pl.drawPoint();
            // 将产生的点与后面的点连线(比较重要的一步)
            for (let j = i + 1; j < this.points.length; j++) {
                const p2 = this.points[j];
                // 计算两个点之间的直线距离
                const d = Math.sqrt((pl.x - p2.x) ** 2 + (pl.y - p2.y) ** 2);
                    // 超出预设范围继续下一次循环
                    if (d > this.maxDis) {
                    continue;
                }
                // 开始绘制直线
                ctx.beginPath();
                ctx.moveTo(pl.x, pl.y);
                ctx.lineTo(p2.x, p2.y);
                ctx.closePath();
                // 设置线的颜色
                // ctx.strokeStyle = "#fff";
                // 渐变的颜色(也是比较重要的一步)
                ctx.strokeStyle = `rgba(25,255,255,${1 - d / this.maxDis})`;
                ctx.stroke();
            }
        }
    }
}

创建实例,并初始化实例,即可得到效果

  const glp = new GraphLinePoint(100, 200);
  glp.drawLinePoint();

动画1122.gif 完整代码

<!DOCTYPE html>
<html lang="en">
  <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>粒子动画</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      canvas {
        background: #000;
        display: block;
        pointer-events: none;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <script>
      // 设置canvas的大小
      const setCanvasSize = () => {
        const window_width = window.innerWidth;
        const window_height = window.innerHeight;
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
      };
      // 窗口变化时重载canvas大小
      window.onresize = function () {
        setCanvasSize();
      };
      window.onmousemove = function (e) {
        console.log(e.offsetX);
        console.log(e.offsetY);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
      };

      // 获取canvas元素
      const canvas = document.querySelector("canvas");
      //   设置大小
      setCanvasSize();
      //   获取canvas上下文对象
      const ctx = canvas.getContext("2d");

      // 获取min到max之间的随机数
      function getRandomNum(min, max) {
        return Math.floor(Math.random() * (max + 1 - min) + min);
      }
      //   生成点的构造函数
      class Point {
        constructor() {
          this.radius = 2;
          this.x = getRandomNum(0, canvas.width - this.radius / 2);
          this.y = getRandomNum(0, canvas.height - this.radius / 2);
          this.xSpeed = getRandomNum(-50, 50);
          this.ySpeed = getRandomNum(-50, 50);
          this.lastDrawTime = null;
        }
        drawPoint() {
          if (this.lastDrawTime) {
            const duration = (Date.now() - this.lastDrawTime) / 1000;
            // 算出距离
            const xDis = this.xSpeed * duration,
              yDis = this.ySpeed * duration;
            //   算出新的坐标
            let x = this.x + xDis,
              y = this.y + yDis;
            //   判断坐标是否超出边界
            if (x > canvas.width - this.radius / 2) {
              x = canvas.width - this.radius / 2;
              this.xSpeed = -this.xSpeed;
            } else if (x < 0) {
              x = 0;
              this.xSpeed = -this.xSpeed;
            }
            if (y > canvas.height - this.radius / 2) {
              y = canvas.height - this.radius / 2;
              this.ySpeed = -this.ySpeed;
            } else if (y < 0) {
              y = 0;
              this.ySpeed = -this.ySpeed;
            }

            this.x = x;
            this.y = y;
          }
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
          ctx.fillStyle = "#fff";
          ctx.fill();
          this.lastDrawTime = Date.now();
        }
      }
      // 构造多个点的类
      class GraphLinePoint {
        constructor(number = 20, maxDis = 200) {
          this.points = new Array(number).fill(0).map(() => new Point());
          this.maxDis = maxDis;
        }
        drawLinePoint() {
          requestAnimationFrame(() => {
            this.drawLinePoint();
          });
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          for (let i = 0; i < this.points.length; i++) {
            const pl = this.points[i];
            pl.drawPoint();
            for (let j = i + 1; j < this.points.length; j++) {
              const p2 = this.points[j];
              const d = Math.sqrt((pl.x - p2.x) ** 2 + (pl.y - p2.y) ** 2);
              if (d > this.maxDis) {
                continue;
              }
              ctx.beginPath();
              ctx.moveTo(pl.x, pl.y);
              ctx.lineTo(p2.x, p2.y);
              ctx.closePath();
              // ctx.strokeStyle = "#fff";
              ctx.strokeStyle = `rgba(25,255,255,${1 - d / this.maxDis})`;
              ctx.stroke();
            }
          }
        }
      }
      const glp = new GraphLinePoint(100, 200);
      glp.drawLinePoint();
    </script>
  </body>
</html>