问题
I'd like to implement click detection for multiple complex shapes on a single canvas element similar to that as realized by CanvasRenderingContext2D.isPointInPath()
.
Obligatory example code below.
HTML:
<canvas id="canvas"></canvas>
<p>In path: <code id="result">false</code></p>
JS:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const result = document.getElementById('result');
ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(105, 25);
ctx.lineTo(25, 105);
ctx.fill();
ctx.beginPath();
ctx.moveTo(125, 45);
ctx.lineTo(45, 125);
ctx.lineTo(125, 125);
ctx.lineTo(205, 45);
ctx.closePath();
ctx.fill();
window.addEventListener('mousemove', e => {
result.innerText = `${ctx.isPointInPath(e.clientX, e.clientY)} X: ${e.clientX} Y: ${e.clientY}`;
});
While the above works well for the last drawn shape, I'd like to be able to perform the same check for any previously drawn shapes.
The project I am working on involves selecting different tiles on an isometric map, so I would like to receive as much information about the selected tile as I can once that tile is clicked on.
I'd rather not have to resort to rendering SVGs due to the amount of shapes I intend to draw. Also, external libraries are undesired and I'm hesitant to draw a pseudo canvas for every shape I draw on the 'visible' canvas just to be able to detect clicks. What alternatives are out there other than waiting for hit regions to come out of experimental status?
I came across a similar, but ultimately different question here: complex shape selection on canvas
回答1:
isPointInPath accepts a Path2D object as optional first argument.
So an easy way is to create such Path2D objects for each of your shapes.
It can even ease your drawing operations, since fill()
and stroke()
also accept these objects:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const result = document.getElementById('result');
const shape1 = new Path2D();
shape1.moveTo(25, 25);
shape1.lineTo(105, 25);
shape1.lineTo(25, 105);
const shape2 = new Path2D();
shape2.moveTo(125, 45);
shape2.lineTo(45, 125);
shape2.lineTo(125, 125);
shape2.lineTo(205, 45);
shape2.closePath();
// to render it
ctx.fill(shape1);
ctx.fill(shape2);
canvas.addEventListener('mousemove', e => {
result.textContent = `
shape1: ${ctx.isPointInPath(shape1, e.offsetX, e.offsetY)}
shape2: ${ctx.isPointInPath(shape2, e.offsetX, e.offsetY)}
X: ${e.offsetX} Y: ${e.offsetY}`;
});
.log { display: inline-block; vertical-align: top}
<canvas id="canvas"></canvas>
<div class="log">In path: <pre id="result">false</pre></div>
来源:https://stackoverflow.com/questions/57789192/click-events-on-complex-canvas-shapes-without-recourse-to-external-libraries