• JavaScript+canvas实现粒子动画效果


    1.HTML部分

    DOCTYPE html>
    <html lang="zh">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>粒子效果title>
        <style>
          canvas {
            position: fixed;
            left: 0;
            top: 0;
            background: #222;
          }
        style>
      head>
    
      <body>
        <canvas>canvas>
        <script src="./js/canvas.js">script>
      body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2.JavaScript部分

    const cvs = document.querySelector('canvas');
    const ctx = cvs.getContext('2d');
    cvs.width = window.innerWidth * window.devicePixelRatio;
    cvs.height = window.innerHeight * window.devicePixelRatio;
    
    /**
     * 获取[min, max]范围内的随机整数
     * @param {number} min
     * @param {number} max
     * @return {number}
     */
    function getRandom(min, max) {
      return Math.floor(Math.random() * (max + 1 - 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(-100, 100);
        this.ySpeed = getRandom(-100, 100); // 每秒钟移动的速度
        // 记录上一次作画的时间 - 知道每一个小段时间的间隔, 计算出移动距离
        this.lastDrawTime = null;
      }
      draw() {
        // 更新坐标
        if (this.lastDrawTime) {
          // 计算新的坐标
          const duration = (Date.now() - this.lastDrawTime) / 1000;
          // 距离
          const xDis = this.xSpeed * duration,
            yDis = this.ySpeed * duration;
    
          // 计算出新的x和y的坐标
          let x = this.x + xDis,
            y = this.y + yDis;
    
          // 判断边界
          if (x > cvs.width - this.r / 2) {
            x = cvs.width - this.r / 2;
            this.xSpeed = -this.xSpeed; // 正的变负的 负的变正的
          } else if (x < 0) {
            x = 0;
            this.xSpeed = -this.xSpeed;
          }
    
          if (y > cvs.height - this.r / 2) {
            y = cvs.height - this.r / 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, 3, 0, 2 * Math.PI);
        ctx.fillStyle = 'rgba(200, 200, 200, 0.8)';
        ctx.fill();
        this.lastDrawTime = Date.now();
      }
    }
    
    class Graph {
      /**
       *
       * @param {number} pointNumber 点的个数
       * @param {number} maxDis 两个点直接的最大距离
       */
      constructor(pointNumber = 100, maxDis = 200) {
        // 生成一系列的点
        this.points = new Array(pointNumber).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];
            ctx.beginPath();
            ctx.moveTo(p1.x, p1.y);
            ctx.lineTo(p2.x, p2.y);
            ctx.closePath();
            // 利用勾股定理计算出两个点之间的距离  **是指数运算符 Math.sqrt()开根号
            const d = Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
            if (d > this.maxDis) {
              continue; // 看下一个点
            }
            ctx.strokeStyle = `rgba(200, 200, 200, ${1 - d / this.maxDis})`;
            ctx.stroke();
          }
          // 两个点它们的距离越远, 颜色就越透明, 越近颜色就越不透明
          // 让点运动起来
        }
      }
    }
    
    // 画直线
    // ctx.beginPath()
    // ctx.moveTo(100, 50)
    // ctx.lineTo(200, 100)
    // ctx.closePath()
    // ctx.strokeStyle = '#fff'
    // // 描边
    // ctx.stroke()
    
    // ctx.beginPath()
    // // 画一个圆
    // ctx.arc(100, 50, 6, 0, 2 * Math.PI)
    // ctx.fillStyle = '#fff'
    // ctx.fill()
    
    // ctx.beginPath()
    // // 画一个圆
    // ctx.arc(200, 100, 6, 0, 2 * Math.PI)
    // ctx.fillStyle = '#fff'
    // ctx.fill()
    
    // const p1 = new Point()
    // const p2 = new Point()
    // p1.draw()
    // p2.draw()
    
    const g = new Graph();
    g.draw();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135

    在这里插入图片描述

  • 相关阅读:
    《机器人SLAM导航核心技术与实战》第1季:第6章_机器人底盘
    MySQL 聚合函数初探
    加密和解密
    SSM学习48:日期型请求参数
    五大类注解和方法注解详解
    Vue3踩坑指南
    21天打卡挑战 - 经典算法之顺序查找
    【luogu SP7685】FLWRS - Flowers(DP)(容斥)
    dot net 杂谈之一
    SSH的原理与配置
  • 原文地址:https://blog.csdn.net/m0_46219714/article/details/133191132