在复杂的画布形状上单击事件,而无需使用外部库 [英] Click events on complex canvas shapes without recourse to external libraries
问题描述
我想在单个画布元素上实现对多个复杂形状的点击检测,类似于 CanvasRenderingContext2D.isPointInPath()
所实现的.
I'd like to implement click detection for multiple complex shapes on a single canvas element similar to that as realized by CanvasRenderingContext2D.isPointInPath()
.
以下强制性示例代码.
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.
由于我打算绘制的形状数量多,我宁愿不必求助于渲染SVG.另外,外部库是不希望的,我很犹豫要为我在可见"画布上绘制的每个形状绘制一个伪画布,以便能够检测到点击.除了等待受灾地区脱离实验状态外,还有哪些其他选择?
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
推荐答案
Path2D 对象作为可选的第一个参数.
isPointInPath
accepts a Path2D object as optional first argument.
一个简单的方法是为每个形状创建此类Path2D对象.
它甚至可以简化您的绘图操作,因为 fill()
和 stroke()
也可以接受以下对象:
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>
这篇关于在复杂的画布形状上单击事件,而无需使用外部库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!