JSFiddle - React, Tailwind, and code Playground

by Ben Gillbanks

HTML

<canvas id="myCanvas"></canvas>

JavaScript

const canvas = document.getElementById('myCanvas');
canvas.width = 400;
canvas.height = 600;
const ctx = canvas.getContext('2d');

// Example: Fill canvas with a demo gradient
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, 'red');
gradient.addColorStop(1, 'blue');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Apply vignette effect
applyVignette(canvas); // Intensity can be adjusted (e.g., 0.5, 1, 2)




function applyVignette(canvas, centerRadius = 0.8, maxDarkness = 0.5) {
    const ctx = canvas.getContext('2d');
    const { width, height } = canvas;

    // Get the canvas image data
    const imageData = ctx.getImageData(0, 0, width, height);
    const data = imageData.data;

    // Calculate constants
    const centerX = width / 2, centerY = height / 2;
    const maxDistance = Math.sqrt(centerX ** 2 + centerY ** 2);
    const innerRadius = centerRadius * maxDistance;
    const scaleFactor = maxDarkness / (maxDistance * (1 - centerRadius));

    // Apply vignette effect pixel by pixel
    for (let i = 0; i < data.length; i += 4) {
        const x = (i / 4) % width;
        const y = Math.floor((i / 4) / width);
        const distance = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);

        const vignetteFactor = distance < innerRadius
            ? 1
            : Math.max(0, 1 - (distance - innerRadius) * scaleFactor);

        // Apply the vignette factor to the RGB channels
        data[i] *= vignetteFactor;     // Red
        data[i + 1] *= vignetteFactor; // Green
        data[i + 2] *= vignetteFactor; // Blue
    }

    // Put the modified image data back onto the canvas
    ctx.putImageData(imageData, 0, 0);
}