Javascript is required!

完整代码如下


const dots = ref<number>(200)

const canvasRef = ref<HTMLCanvasElement | null>(null);
const init = () => {
  const canvas = canvasRef.value;
  if (!canvas) return;

  const ctx = canvas.getContext('2d');
  if (!ctx) return;

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  canvas.style.backgroundColor = 'black';

  return ctx;
};

const getRandom = (min: number, max: number) => {
  return Math.floor(Math.random() * (max - min + 1)) + min;
};

class Point {
  r: number;
  x: number;
  y: number;
  vx: number; // x轴速度
  vy: number; // y轴速度

  constructor(canvas: HTMLCanvasElement) {
    this.r = 1.5;
    this.x = getRandom(this.r, canvas.width - this.r);
    this.y = getRandom(this.r, canvas.height - this.r);
    this.vx = Math.random() * 2 - 1; // -1到1之间的随机速度
    this.vy = Math.random() * 2 - 1;
  }

  draw(ctx: CanvasRenderingContext2D | undefined) {
    if (!ctx) return;

    ctx.beginPath()
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true)
    ctx.fillStyle = '#fff'
    ctx.fill();
  }

  update(canvas: HTMLCanvasElement) {
    this.x += this.vx;
    this.y += this.vy;

    // 边界检测,碰到边缘反弹
    if (this.x <= this.r || this.x >= canvas.width - this.r) {
      this.vx = -this.vx;
    }
    if (this.y <= this.r || this.y >= canvas.height - this.r) {
      this.vy = -this.vy;
    }
  }
}

class Graph {
  points: Point[];
  maxDistance = 200;
  canvas: HTMLCanvasElement;
  constructor(canvas: HTMLCanvasElement, length: number = 100) {
    this.canvas = canvas;
    this.points = Array.from({ length }, () => {
      return new Point(canvasRef.value!);
    });
  }

  addPoint(num: number) {
    this.points.push(...Array.from({ length: num }, () => {
      return new Point(this.canvas);
    }));
  }

  update() {
    this.points.forEach(point => point.update(this.canvas));
  }

  draw(ctx: CanvasRenderingContext2D) {
    if (!ctx) return;
    ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

    for (let i = 0; i < this.points.length; i++) {
      const prevPoint = this.points[i];
      prevPoint.draw(ctx);

      for (let j = i + 1; j < this.points.length; j++) {
        const nextPoint = this.points[j];
        const distance = Math.sqrt(
          Math.pow(prevPoint.x - nextPoint.x, 2) +
          Math.pow(prevPoint.y - nextPoint.y, 2)
        );
        if (distance > this.maxDistance) continue;

        ctx.beginPath();
        ctx.moveTo(prevPoint.x, prevPoint.y);
        ctx.lineTo(nextPoint.x, nextPoint.y);
        ctx.strokeStyle = `rgba(255, 255, 255, 1 - distance / this.maxDistance)`;
        // ctx.strokeStyle = '#fff'
        ctx.lineWidth = 0.5;
        ctx.stroke();
      }
    }
  }
}

onMounted(() => {
  const ctx = init();
  const graph = new Graph(canvasRef.value!, dots.value);
  function animate() {
    graph.update();
    if (!ctx) return;
    graph.draw(ctx);
    requestAnimationFrame(animate);
  }
  animate();
  const btn = document.querySelector('.add-btn')
  btn?.addEventListener('click', () => {
    dots.value += 10;
    graph.addPoint(10);
  })
})