Draws a heart shape on a canvas
by Arjan Haverkamp
JavaScript
function vignetteHeart(width, height, innerPercent) {
// Clamp innerPercent between 0 and 1
const pct = Math.max(0, Math.min(innerPercent, 1));
const size = Math.min(width,height);
// Create and size the canvas
const canvas = document.createElement('canvas'), ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
//
// Draw white vignette
//
// Center coordinates
const cx = width / 2;
const cy = height / 2;
// Radii for full canvas bounds
const rx1 = width / 2;
const ry1 = height / 2;
// Use context transformation to draw an elliptical gradient
ctx.save();
ctx.translate(cx, cy);
// Scale a unit circle into an ellipse matching the canvas aspect ratio
ctx.scale(rx1, ry1);
// In scaled space: inner radius is pct (unit circle fraction), outer radius √2 reaches corners
const r0 = pct;
const r1 = Math.SQRT2;
const gradient = ctx.createRadialGradient(0, 0, r0, 0, 0, r1);
gradient.addColorStop(0, 'rgba(255,0,255,0)');
gradient.addColorStop(1, 'rgba(255,0,255.7)');
ctx.fillStyle = gradient;
// Fill a 2×2 square in scaled coordinates, which maps to the full canvas
ctx.fillRect(-1, -1, 2, 2);
ctx.restore();
//
// Draw heart shape
//
const HEART_PATH = 'M8 1.314C12.438-3.248 23.534 4.735 8 15C-7.534 4.736 3.562-3.248 8 1.314';
const path = new Path2D(HEART_PATH);
const padding = Math.round(Math.min(width, height) / 15);
const size2 = Math.min(width, height) - 2*padding;
ctx.save()
const scale = size2 / 16
ctx.translate(padding, padding);
ctx.scale(scale, scale)
ctx.lineWidth = .1;
ctx.stroke(path)
ctx.restore()
return canvas;
}
const canvas = vignetteHeart(600, 800, .7);
document.body.append(canvas)