找出一个点是否在一条直线上。

5

假设我在HTML5画布中绘制了一条线:

...
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x1,y1);
ctx.closePath();
...

我希望能够确定鼠标按下事件是否发生在这条线上,我有如下代码:

var handleMouseDown = function(e) {
  var coords = translateCoords(e.x,e.y);
  ...
  if (ctx.isPointInPath(coords.x, coords.y) {
    ...

现在,这段代码在处理圆形和矩形方面运行良好,但对于线条则不行。我有两个问题:

  1. 我的想法是调用closePath()函数处理线条本身是不正确的。问题 - 如何检查鼠标按下事件是否发生在该线上?

  2. 如何扩展这个功能以查找鼠标按下事件是否发生在线附近?

3个回答

9
第一步是在直线上找到点的正常投影。这其实非常简单:计算点1到目标的距离,以及点2到目标的距离,分别称为D1和D2。然后计算D1 + (D2 - D1) / 2。这是从点1到直线上投影点的距离。
现在你可以找到该点,并获得该点到目标的距离。如果距离为零,则目标恰好在直线上。如果距离小于5,则目标距离小于5像素,依此类推。
编辑:一张图片胜过千言万语。这里是一个图表:
Diagram
(来源: adamhaskell.net) (回想起来,可能应该用不同的颜色表示那些圆圈...另外,紫色线应该垂直于AB线. 蓝线的方向问题请忽略!)

1
嗯,尽管这对于线条来说很好用,但我想其他一维路径(如弧线或曲线)可能需要不同的解决方案。也许下面的解决方案会更好。 - appa

7

这里是从维基百科文章距离点到线的方法(由两个点定义的线)中采用的方法。

        var Dx = x2 - x1;
        var Dy = y2 - y1;
        var d = Math.abs(Dy*x0 - Dx*y0 - x1*y2+x2*y1)/Math.sqrt(Math.pow(Dx, 2) + Math.pow(Dy, 2));

其中,(x0,y0) 是您的点坐标,而您的线是 ((x1,y1),(x2,y2))。 不过,这并没有检查线的边界,因此我需要添加另一个检查。

    function inBox(x0, y0, rect) {
        var x1 = Math.min(rect.startX, rect.startX + rect.w);
        var x2 = Math.max(rect.startX, rect.startX + rect.w);
        var y1 = Math.min(rect.startY, rect.startY + rect.h);
        var y2 = Math.max(rect.startY, rect.startY + rect.h);
        return (x1 <= x0 && x0 <= x2 && y1 <= y0 && y0 <= y2);
    }

如果您将您的行定义为矩形,希望这可以帮助到您。


1
你有两个选项。你的“简单”选项是使用画布来完成它——读取鼠标所在位置的像素数据,如果它与你的线条颜色相同,则用户点击了该线条。然而,这样做需要很多假设,比如你的画布上的所有东西都是以不同的纯色渲染的。这是可能的,因为一个常见的技巧是将所有东西渲染到一个屏幕外的画布中,使用不同的纯色。然后当用户点击某些东西时,通过读取那个像素的颜色并将其映射回原始对象,你就知道它是什么了。
但这不完全是你要求的 :)
你不想知道用户是否点击了一条线,因为他们几乎永远不会这样做。一条线是无限细的,所以除非它恰好水平或垂直,否则他们永远不会点击它。相反,你想知道鼠标离线有多远。Kolink刚刚回答了这部分,所以我就到这里吧 :)

谢谢 - 我应该考虑使用一个离屏画布来完成我目前正在做的事情。 - appa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接