HTML Canvas line animation

Ming Sun

Ming Sun / May 08, 2023

4 min read––– views

React component

The following code will create a boiler template for HTML canvas.

import { useEffect } from "react";

const mouse = { x: 0, y: 0 };

class FlowFieldEffect {
  #ctx;
  #width;
  #height;
  constructor(ctx, width, height) {
    this.#ctx = ctx;
    this.#ctx.lineWidth = 0.5;
    this.#width = width;
    this.#height = height;
    this.#ctx.strokeStyle = "white";
    this.lastTime = 0;
    this.interval = 1000 / 120;
    this.timer = 0;
    this.cellSize = 12;
    this.gradient;
    this.createGradient();
    this.#ctx.strokeStyle = this.gradient;
    this.radius = 0;
    this.vr = 0.01;
  }

  createGradient() {
    this.gradient = this.#ctx.createLinearGradient(
      0,
      0,
      this.#width,
      this.#height
    );
    this.gradient.addColorStop("0.1", "#ff5c33");
    this.gradient.addColorStop("0.2", "#ff66b3");
    this.gradient.addColorStop("0.3", "#ccccff");
    this.gradient.addColorStop("0.4", "#b3ffff");
    this.gradient.addColorStop("0.8", "#80ff80");
    this.gradient.addColorStop("0.9", "#ffff33");
  }

  drawLine(angle, x, y) {
    let positionX = x;
    let positionY = y;
    let dx = mouse.x - positionX;
    let dy = mouse.y - positionY;
    const length = 30;
    this.#ctx.beginPath();
    this.#ctx.moveTo(x, y);
    this.#ctx.lineTo(
      x + Math.cos(angle) * length,
      y + Math.sin(angle) * length
    );
    this.#ctx.stroke();
  }

  animate(timeStamp) {
    const deltaTime = timeStamp - this.lastTime;
    this.lastTime = timeStamp;
    this.radius += this.vr;

    if (this.radius > 10 || this.radius < -10) {
      this.vr *= -1;
    }

    if (this.timer > this.interval) {
      this.#ctx.clearRect(0, 0, this.#width, this.#height);

      for (let y = 0; y < this.#height; y += this.cellSize) {
        for (let x = 0; x < this.#width; x += this.cellSize) {
          const angle = this.radius * (Math.cos(x * 0.01) + Math.sin(y * 0.01));
          this.drawLine(angle, x, y);
        }
      }

      this.timer = 0;
    } else {
      this.timer += deltaTime;
    }

    requestAnimationFrame(this.animate.bind(this));
  }
}

const CanvasLineAnimation = () => {
  useEffect(() => {
    const canvasParent = document.getElementById("canvasParent");
    const canvas = document.getElementById("canvas1");
    canvas.style.background = "black";
    const ctx = canvas.getContext("2d");
    canvas.width = canvasParent.offsetWidth;
    canvas.height = 800;
    const flowField = new FlowFieldEffect(ctx, canvas.width, canvas.height);
    flowField.animate(0);

    canvas.addEventListener("mousemove", function (e) {
      mouse.x = e.offsetX;
      mouse.y = e.offsetY;
    });
  }, []);

  return (
    <div id="canvasParent" className="w-full">
      <canvas id="canvas1"></canvas>
    </div>
  );
};

export default CanvasLineAnimation;

References and downloads

[1] HTML Canvas DEEP DIVE


HomeWikis
SnippetsAbout
Google ScholarLinkedIn