<canvas width="120px" height="100px"></canvas>

<p>Canvas <span id="svg_state">is not</span> being interacted with.</p>

<p>Cloud edge <span id="cloud_state">is not</span> being interacted with</p>

<p>Mouse coordinates: <span id="mouse_coords"></span></p>
canvas {
	width: 50%;
	max-width: 200px;
	border: 1px dashed black;
}
//  @ts-check

const canvasStateDisplay = document.querySelector('#svg_state');
const cloudStateDisplay = document.querySelector('#cloud_state');
const mouseCoordsDisplay = document.querySelector('#mouse_coords');
let canvasInteracting = false;
let cloudInteracting = false;
let translatedMouseCoords = { x: 0, y: 0 };

const cloudSvg = document.querySelector('svg');
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

/**
 * For a given mouse coordinate, translate to corresponding coordinate within original canvas element
 * @param mouseEvent {{clientX: number, clientY: number}}
 * @param canvasElem {HTMLCanvasElement}
 */
function getCanvasCoords(mouseEvent, canvasElem) {
	const canvasBoundingRect = canvasElem.getBoundingClientRect();
	const scale = {
		x: canvasElem.width / canvasBoundingRect.width,
		y: canvasElem.height / canvasBoundingRect.height,
	};
	return {
		x: (mouseEvent.clientX - canvasBoundingRect.left) * scale.x,
		y: (mouseEvent.clientY - canvasBoundingRect.top) * scale.y,
	};
}

function updateDisplay() {
	canvasStateDisplay.textContent = canvasInteracting ? 'is' : 'is not';
	cloudStateDisplay.textContent = cloudInteracting ? 'is' : 'is not';
	mouseCoordsDisplay.textContent = JSON.stringify(translatedMouseCoords);
}

// Insert cloud into canvas
const cloudSvgPath = `m31.93768,83.56317a24.64828,23.57661 0 0 1 0,-48.2249a26.79161,24.11245 0 0 1 58.94155,10.71664l5.35832,0a18.75413,18.75413 0 0 1 0,37.50826l-64.29987,0`;
const cloudPath = new Path2D(cloudSvgPath);
ctx.lineWidth = 3;
ctx.strokeStyle = 'black';
ctx.stroke(cloudPath);

/**
 * @param evt {MouseEvent}
 */
function hitDetect(evt) {
	// Canvas might be offset and/or scaled, so have to translate mouse position to *original* canvas coordinates
	translatedMouseCoords = getCanvasCoords(evt, canvas);
	cloudInteracting = ctx.isPointInStroke(cloudPath, translatedMouseCoords.x, translatedMouseCoords.y);
	updateDisplay();
}

// Attach mouse listener to entire canvas
canvas.addEventListener('mousemove', (evt) => {
	canvasInteracting = true;
	hitDetect(evt);
});
canvas.addEventListener('mouseleave', (evt) => {
	canvasInteracting = false;
	cloudInteracting = false;
	updateDisplay();
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.