<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();
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.