【问题标题】:Click events on complex canvas shapes without recourse to external libraries无需借助外部库即可在复杂的画布形状上单击事件
【发布时间】:2019-09-04 23:16:44
【问题描述】:

我想在单个画布元素上实现对多个复杂形状的点击检测,类似于 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。此外,外部库是不受欢迎的,我很犹豫是否为我在“可见”画布上绘制的每个形状绘制一个伪画布,以便能够检测到点击。除了等待命中区域退出实验状态之外,还有哪些选择?

我在这里遇到了一个类似但最终不同的问题:complex shape selection on canvas

【问题讨论】:

    标签: canvas mouseevent mouselistener


    【解决方案1】:

    isPointInPath 接受 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>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-04
      • 1970-01-01
      • 2021-11-08
      • 2022-10-06
      • 1970-01-01
      • 2011-02-17
      • 2013-05-29
      • 2015-04-15
      相关资源
      最近更新 更多