在不求助于外部库的情况下单击复杂 canvas 形状上的事件
Click events on complex canvas shapes without recourse to external libraries
我想在单个 canvas 元素上实现多个复杂形状的点击检测,类似于 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}`;
});
虽然以上方法适用于最后绘制的形状,但我希望能够对之前绘制的任何形状执行相同的检查。
我正在进行的项目涉及在等距地图上选择不同的图块,因此我希望在单击该图块后尽可能多地接收有关所选图块的信息。
由于我打算绘制的形状数量太多,我宁愿不必诉诸渲染 SVG。此外,外部库是不受欢迎的,我犹豫是否为我在 'visible' canvas 上绘制的每个形状绘制伪 canvas 只是为了能够检测点击。除了等待受灾地区退出实验状态之外,还有什么其他选择?
我在这里遇到了一个类似但最终不同的问题:complex shape selection on canvas
isPointInPath
accepts a Path2D 对象作为可选的第一个参数。
所以一个简单的方法是为每个形状创建这样的 Path2D 对象。
它甚至可以简化您的绘图操作,因为 fill()
和 stroke()
也接受这些对象:
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>
我想在单个 canvas 元素上实现多个复杂形状的点击检测,类似于 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}`;
});
虽然以上方法适用于最后绘制的形状,但我希望能够对之前绘制的任何形状执行相同的检查。
我正在进行的项目涉及在等距地图上选择不同的图块,因此我希望在单击该图块后尽可能多地接收有关所选图块的信息。
由于我打算绘制的形状数量太多,我宁愿不必诉诸渲染 SVG。此外,外部库是不受欢迎的,我犹豫是否为我在 'visible' canvas 上绘制的每个形状绘制伪 canvas 只是为了能够检测点击。除了等待受灾地区退出实验状态之外,还有什么其他选择?
我在这里遇到了一个类似但最终不同的问题:complex shape selection on canvas
isPointInPath
accepts a Path2D 对象作为可选的第一个参数。
所以一个简单的方法是为每个形状创建这样的 Path2D 对象。
它甚至可以简化您的绘图操作,因为 fill()
和 stroke()
也接受这些对象:
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>