canvas - page background bubble effect code interpretation

1. Look at the effect first

insert image description here

2. Source code

<!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>Document</title>
</head>

<body>
  <canvas id="canvas"></canvas>
</body>
<style>
  body {
      
      
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAI0lEQVQIW2NkwAT/GdHE/gP5jMiCYAGQIpggXAAmiCIAEgQAAE4FBbECyZcAAAAASUVORK5CYII=) #222;
  }
</style>

<script>
  class Particles {
      
      
    constructor() {
      
      
      // 泡泡的颜色列表
      this.colors = ['255, 255, 255', '255, 99, 71', '19, 19, 19'];
      // 泡泡是否需要渐变,这里都是要渐变的
      this.blurry = true;
      //adds white border
      this.border = false;
      // 泡泡的半径范围
      this.minRadius = 10;
      this.maxRadius = 35;
      // 泡泡的透明度范围
      this.minOpacity = 0.005;
      this.maxOpacity = 0.5;
      //particle speed min/max
      this.minSpeed = 0.05;
      this.maxSpeed = 0.5;
      //frames per second
      this.fps = 60;
      // 页面中泡泡的数量
      this.numParticles = 175;
      //required canvas variables
      this.canvas = document.getElementById('canvas');
      this.ctx = this.canvas.getContext('2d');
    }

    init() {
      
      
      this.render();
      this.createCircle();
    }

    _rand(min, max) {
      
      
      return Math.random() * (max - min) + min;
    };

    // canvas基本配置
    render() {
      
      
      var self = this;
      var wHeight = window.innerHeight;
      var wWidth = window.innerWidth;

      self.canvas.width = wWidth;
      self.canvas.height = wHeight;

      window.addEventListener('resize', () => self.render);
    };

    // 创建泡泡
    createCircle() {
      
      
      var particle = [];

      for (var i = 0; i < this.numParticles; i++) {
      
      
        var self = this;
        // ~~ 是将某一数据转换成数字类型的写法,类似!!的转换成Boolean类型的用法
        // 所以这里是取颜色列表里的某个随机颜色
        var color = self.colors[~~self._rand(0, self.colors.length)];

        // 保存所有的泡泡
        particle[i] = {
      
      
          radius: self._rand(self.minRadius, self.maxRadius), // 半径
          xPos: self._rand(0, canvas.width), // 初始x轴位置
          yPos: self._rand(0, canvas.height), // 初始y轴位置
          xVelocity: self._rand(self.minSpeed, self.maxSpeed), // x轴运行速度
          yVelocity: self._rand(self.minSpeed, self.maxSpeed), // y轴运行速度
          color: `rgba(${ 
        color},${ 
        self._rand(self.minOpacity, self.maxOpacity)})` // 随机的颜色+随机的透明度
        };

        self.draw(particle, i);
      }
      // 所有的泡泡绘制结束以后,开始执行动画
      self.animate(particle, this);
    };

    draw(particle, i) {
      
      
      var self = this;
      var ctx = self.ctx;

      if (self.blurry === true) {
      
      
        // 泡泡的渐变设置
        var grd = ctx.createRadialGradient(
          particle[i].xPos,
          particle[i].yPos,
          particle[i].radius, // 里面的圆。对应 1
          particle[i].xPos,
          particle[i].yPos,
          particle[i].radius / 1.5 // 外面的圆。对应 0
        );

        grd.addColorStop(0.0, 'rgba(34, 34, 34, 0)'); // 0:外面圆的最终渐变色
        grd.addColorStop(1.0, particle[i].color); // 1:中心圆的渐变色
        ctx.fillStyle = grd;
      } else {
      
      
        // 根本不会走到这一步
        ctx.fillStyle = particle[i].color;
      }

      if (self.border === true) {
      
      
        ctx.strokeStyle = '#fff';
        ctx.stroke();
      }

      ctx.beginPath();
      // 画出泡泡
      ctx.arc(
        particle[i].xPos,
        particle[i].yPos,
        particle[i].radius,
        0,
        2 * Math.PI,
        false
      );
      ctx.fill();
    };

    animate(particle, self) {
      
      
      // var self = this;
      var ctx = self.ctx;
      self.clearCanvas();

      setInterval(function () {
      
      
        self.clearCanvas();
        for (var i = 0; i < self.numParticles; i++) {
      
      

          // 增加x,y轴的偏移量
          particle[i].xPos += particle[i].xVelocity;
          particle[i].yPos -= particle[i].yVelocity;

          // 防止泡泡抛出屏幕
          if (
            particle[i].xPos > self.canvas.width + particle[i].radius ||
            particle[i].yPos > self.canvas.height + particle[i].radius
          ) {
      
      
            self.resetParticle(particle, i);
          } else {
      
      
            self.draw(particle, i);
          }
        }
      }, 1000 / self.fps);

    };

    resetParticle(particle, i) {
      
      
      var self = this;

      var random = self._rand(0, 1);

      if (random > 0.5) {
      
      
        // 从左边出来
        particle[i].xPos = -particle[i].radius; 
        particle[i].yPos = self._rand(0, canvas.height);
      } else {
      
      
        // 从底部出来
        particle[i].xPos = self._rand(0, canvas.width);
        particle[i].yPos = canvas.height + particle[i].radius;
      }
      self.draw(particle, i);
    };

    clearCanvas() {
      
      
      this.ctx.clearRect(0, 0, canvas.width, canvas.height);
    };

  }
  // 初始化
  var particle = new Particles();
  particle.init();
</script>

</html>

3. Realize ideas

This implementation idea is relatively simple:

  • It is a drawing of bubbles one by one, each bubble has an initial position and initial movement direction
  • Increase the offset of the x and y axes through the loop timer, and then redraw the bubble
  • Randomly reset the initial position of the bubble when the bubble reaches the edge of the screen, and then continue to draw the bubble

Among them, the createRadialGradient method is used to process the edge gradient of the bubble . The circles of the first three parameters correspond to addColorStopthe gradient color when the first parameter is 1; the circles of the latter three parameters correspond to the gradient color when the first parameter is 0.

Guess you like

Origin blog.csdn.net/vet_then_what/article/details/125624126