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)