OWolf

2024-09-30 Design

Create a Dynamic Noisy Logo Using Canvas and SVG in React

By O. Wolfson

In this article, we’ll explore how to create an animated noisy logo effect using HTML canvas and SVG in React. This effect generates random noise on a canvas and reveals the noise through an SVG logo using a mask. This technique can be used for branding, digital art, or creative web animations.

Key Concepts

  1. HTML Canvas: Used to generate dynamic noise with JavaScript.
  2. SVG: A scalable vector graphic used to define the logo and apply the mask.
  3. React: A JavaScript library for building UI components.

Step-by-Step Breakdown

Let’s walk through the code and explain how each part works.

1. Initial Setup

First, we import the necessary React hooks useEffect and useRef. We use useEffect to run the canvas drawing code after the component is rendered and useRef to access the canvas DOM element.

javascript
"use client"; // Ensures the component is client-side

import { useEffect, useRef } from "react";

2. Canvas Noise Generation

Next, we create the NoisyLogo component. Inside this component, we define a canvasRef using useRef to target the <canvas> element within the component.

javascript
export default function NoisyLogo() {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas?.getContext("2d");
    if (!ctx) return;

    const width = 1378;
    const height = 562;
    canvas.width = width;
    canvas.height = height;

2.1. Generate Noise Function

We define a function generateNoise() that generates random noise on the canvas. It creates an ImageData object that holds pixel data for the canvas. By looping over each pixel and assigning a random value to the red, green, and blue channels, we create a noise effect.

javascript
function generateNoise() {
  const imageData = ctx?.createImageData(width, height);
  if (!imageData) return;
  for (let i = 0; i < imageData.data.length; i += 4) {
    const value = Math.random() * 255;
    imageData.data[i] = value; // Red
    imageData.data[i + 1] = value; // Green
    imageData.data[i + 2] = value; // Blue
    imageData.data[i + 3] = 255; // Alpha (opacity)
  }
  ctx?.putImageData(imageData, 0, 0);
}

2.2. Animation with requestAnimationFrame

To continuously update the noise, we use requestAnimationFrame within the render function. This ensures that the noise is constantly redrawn, giving it a dynamic "fuzzy TV screen" effect.

javascript
    const render = () => {
      generateNoise();
      requestAnimationFrame(render);
    };

    render();
  }, []);

3. SVG Mask and Logo

Now, let's move to the SVG part. The <svg> element contains the mask and logo that will reveal the noise generated by the canvas. We define a mask using the id="noise-mask" attribute. Inside the mask, we use two <rect> elements: one for the black border and one for the white-filled area that defines the mask's shape.

3.1. SVG Mask Definition

The black area hides the noise, and the white area reveals it. The logo path is placed inside the mask and is defined by a complex <path> element that describes the SVG shape of the logo.

javascript
  return (
    <svg
      width="600"
      height="245"
      viewBox="0 0 1378 562"
      xmlns="http://www.w3.org/2000/svg"
      style={{ display: "block" }}
    >
      {/* Define the mask using the SVG logo */}
      <mask id="noise-mask">
        {/* Add a black border */}
        <rect width="100%" height="100%" fill="black" />
        {/* The white part for the mask content */}
        <rect width="98%" height="98%" fill="white" x="1%" y="1%" />
        <g
          transform="translate(0.000000,562.000000) scale(0.100000,-0.100000)"
          fill="black"
        >
          <path d="M0 2810 l0 -2810 6890 0 6890 0 0 2810 0 2810 -6890 0 -6890 0 0 -2810z m11960 1630 c102 -9 340 -46 348 -55 4 -3 -106 -556 -110 -560 -2 -2 -37 3 -78 11 -133 23 -204 15 -259 -32 -34 -28 -54 -103 -49 -176 l3 -43 208 -3 207 -2 0 -285 0 -285 -210 0 -210 0 0 -805 0 -805 -390 0 -390 0 0 805 0 805 -175 0 -175 0 0 285 0 285 175 0 175 0 0 78 c0 99 23 239 54 331 98 289 348 451 711 460 28 0 102 -4 165 -9z" />
          {/* More path definitions */}
        </g>
      </mask>

3.2. Embedding the Canvas in the SVG

Finally, we embed the canvas inside the SVG using <foreignObject>. This element allows us to render regular HTML inside the SVG. The mask="url(#noise-mask)" attribute is applied to the <foreignObject> to apply the mask we defined earlier. This causes the canvas noise to be revealed through the SVG logo shape.

javascript
      {/* Embed the canvas inside the SVG using <foreignObject> */}
      <foreignObject width="100%" height="100%" mask="url(#noise-mask)">
        <canvas ref={canvasRef} className="w-full h-full" />
      </foreignObject>
    </svg>
  );
}

Key Points to Remember

  • Canvas Drawing: The canvas draws random noise using the generateNoise function.
  • Masking in SVG: The SVG mask is defined to reveal certain parts of the canvas noise through the logo.
  • React Hooks: We use useEffect to generate the noise when the component is mounted, and useRef to target the canvas element.
  • Dynamic Updates: The requestAnimationFrame ensures continuous updates to the noise, creating a dynamic effect.

Conclusion

This combination of HTML canvas and SVG in React allows you to create visually striking, animated effects with ease. By leveraging masks in SVG, we can control where the canvas noise is displayed, resulting in a unique logo animation.

This technique can be adapted for various purposes, such as animated backgrounds, interactive elements, or creative web designs.