js implements particle clock special effects (Duyi)

js to achieve particle clock special effects

Source code:
JS

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d', {
    
    
  willReadFrequently: true,
});

function initCanvasSize() {
    
    
  canvas.width = window.innerWidth * devicePixelRatio;
  canvas.height = window.innerHeight * devicePixelRatio;
}

initCanvasSize();

/**
 * 获取 [min, max] 范围内的随机整数
 */
function getRandom(min, max) {
    
    
  return Math.floor(Math.random() * (max + 1 - min) + min);
}

class Particle {
    
    
  constructor() {
    
    
    const r = Math.min(canvas.width, canvas.height) / 2;
    const cx = canvas.width / 2;
    const cy = canvas.height / 2;
    const rad = (getRandom(0, 360) * Math.PI) / 180;
    this.x = cx + r * Math.cos(rad);
    this.y = cy + r * Math.sin(rad);
    this.size = getRandom(2 * devicePixelRatio, 7 * devicePixelRatio);
  }

  draw() {
    
    
    ctx.beginPath();
    ctx.fillStyle = '#5445544d';
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.fill();
  }

  moveTo(tx, ty) {
    
    
    const duration = 500; // 500ms的运动时间
    const sx = this.x,
      sy = this.y;
    const xSpeed = (tx - sx) / duration;
    const ySpeed = (ty - sy) / duration;
    const startTime = Date.now();
    const _move = () => {
    
    
      const t = Date.now() - startTime;
      const x = sx + xSpeed * t;
      const y = sy + ySpeed * t;
      this.x = x;
      this.y = y;
      if (t >= duration) {
    
    
        this.x = tx;
        this.y = ty;
        return;
      }
      // x,y改动一点
      requestAnimationFrame(_move);
    };
    _move();
  }
}

const partciles = [];
let text = null;
function clear() {
    
    
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

function draw() {
    
    
  clear();
  update();
  partciles.forEach((p) => p.draw());
  requestAnimationFrame(draw);
}

draw();

function getText() {
    
    
  return new Date().toTimeString().substring(0, 8);
}

function update() {
    
    
  const newText = getText();
  if (newText === text) {
    
    
    return;
  }
  clear();
  text = newText;
  // 画文本
  const {
    
     width, height } = canvas;
  ctx.fillStyle = '#000';
  ctx.textBaseline = 'middle';
  ctx.font = `${
      
      140 * devicePixelRatio}px 'DS-Digital', sans-serif`;
  ctx.fillText(text, (width - ctx.measureText(text).width) / 2, height / 2);
  const points = getPoints();
  clear();
  for (let i = 0; i < points.length; i++) {
    
    
    let p = partciles[i];
    if (!p) {
    
    
      p = new Particle();
      partciles.push(p);
    }
    const [x, y] = points[i];
    p.moveTo(x, y);
  }
  if (points.length < partciles.length) {
    
    
    partciles.splice(points.length);
  }
}

function getPoints() {
    
    
  const {
    
     width, height, data } = ctx.getImageData(
    0,
    0,
    canvas.width,
    canvas.height
  );
  const points = [];
  const gap = 6;
  for (let i = 0; i < width; i += gap) {
    
    
    for (let j = 0; j < height; j += gap) {
    
    
      const index = (i + j * width) * 4;
      const r = data[index];
      const g = data[index + 1];
      const b = data[index + 2];
      const a = data[index + 3];
      if (r === 0 && g === 0 && b === 0 && a === 255) {
    
    
        points.push([i, j]);
      }
    }
  }
  return points;
}

HTML

<!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: radial-gradient(#fff, #8c738c);
        display: block;
        width: 100vw;
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <script src="./index.js"></script>
  </body>
</html>

Take it all, click a like and collect it~~~

Guess you like

Origin blog.csdn.net/qq_53461589/article/details/130930147