Click events on complex canvas shapes without recourse to external libraries

有些话、适合烂在心里 提交于 2021-02-05 11:25:49

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!