HTML Canvas matrix rain

Ming Sun

Ming Sun / May 08, 2023

4 min read––– views

React component

The following code will create a matrix pixel rain effect on HTML canvas.

import { useEffect } from "react";

class Symbol {
  constructor(x, y, fontSize, canvasHeight) {
    this.characters =
      "アァカサタナハマヤャラワガザダバパ∆∑π∆√∫µ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹";
    this.x = x;
    this.y = y;
    this.fontSize = fontSize;
    this.text = "";
    this.canvasHeight = canvasHeight;
  }

  draw(context) {
    this.text = this.characters.charAt(
      Math.floor(Math.random() * this.characters.length)
    );
    context.fillText(this.text, this.x * this.fontSize, this.y * this.fontSize);
    if (this.y * this.fontSize > this.canvasHeight && Math.random() > 0.98) {
      this.y = 0;
    } else {
      this.y += 1;
    }
  }
}

class Effect {
  constructor(canvasWidth, canvasHeight) {
    this.canvasWidth = canvasWidth;
    this.canvasHeight = canvasHeight;
    this.fontSize = 15;
    this.columns = this.canvasWidth / this.fontSize;
    this.symbols = [];
    this.initialize();
  }
  initialize() {
    for (let i = 0; i < this.columns; i++) {
      this.symbols[i] = new Symbol(i, 0, this.fontSize, this.canvasHeight);
    }
  }
}

const CanvasMatrixRain = () => {
  useEffect(() => {
    let canvasParent = document.getElementById("canvasParent");
    let canvas = document.getElementById("canvas1");
    canvas.style.background = "black";
    let ctx = canvas.getContext("2d");
    canvas.width = canvasParent.offsetWidth;
    canvas.height = 400;

    let mouse = { x: undefined, y: undefined };

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

    const effect = new Effect(canvas.width, canvas.height);

    const gradient = ctx.createLinearGradient(
      0,
      0,
      canvas.width,
      canvas.height
    );

    gradient.addColorStop("0.1", "#ff5c33");
    gradient.addColorStop("0.2", "#ff66b3");
    gradient.addColorStop("0.3", "#ccccff");
    gradient.addColorStop("0.4", "#b3ffff");
    gradient.addColorStop("0.8", "#80ff80");
    gradient.addColorStop("0.9", "#ffff33");

    let lastTime = 0;
    let timer = 0;
    const fps = 10;
    const nextFrame = 1000 / fps;

    function animate(timeStamp) {
      const deltaTime = timeStamp - lastTime;
      lastTime = timeStamp;

      if (timer > nextFrame) {
        ctx.font = effect.fontSize + "px monospace";
        ctx.fillStyle = "rgba(0,0,0, 0.05)";
        ctx.textAlign = "center";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = gradient;
        for (let i = 0; i < effect.symbols.length; i++) {
          effect.symbols[i].draw(ctx);
        }
        timer = 0;
      } else {
        timer += deltaTime;
      }

      requestAnimationFrame(animate);
    }

    animate(0);
  }, []);

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

export default CanvasMatrixRain;

References and downloads

[1] Matrix Rain Experiments in JavaScript (tutorial)


HomeWikis
SnippetsAbout
Google ScholarLinkedIn