【问题标题】:Finding if a point is on a line查找一个点是否在一条线上
【发布时间】:2013-01-17 03:35:46
【问题描述】:

假设我在 HTML5 Canvas 中画了一条线:

...
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. 如何扩展此功能以查找鼠标按下事件是否发生在 线附近?

【问题讨论】:

    标签: javascript html html5-canvas


    【解决方案1】:

    第一步是找到点在直线上的法线投影。这其实很简单:取点 1 到目标的距离,以及点 2 到目标的距离,分别称它们为 D1 和 D2。然后计算D1+(D2-D1)/2。这是从点 1 到直线上投影点的距离。

    您现在可以找到该点,并获取从该点到目标的距离。如果距离为零,则目标正好在线上。如果距离小于 5,则目标距离小于 5px,以此类推。

    编辑:一张图片值一千字。这是一个图表:


    (来源:adamhaskell.net

    (事后看来,可能应该让这些圆圈变成不同的颜色......另外,紫色线应该垂直于线 AB。用蓝色线怪我的糟糕目标!)

    【讨论】:

    • 谢谢 - 很棒的答案,非常感谢您的帮助!
    • 嗯,虽然这对线条很有效,但我想我需要为其他一维路径(如弧线或曲线)提供不同的解决方案。也许下面的解决方案会更好。
    【解决方案2】:

    这是取自维基百科文章Distance from a point to a line (Line defined by two points)的方法

            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) 是您的 Point 坐标,您的 Line 是 ((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);
        }
    

    您的 Line 定义为矩形。希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      您有两种选择。您的“简单”选项是使用画布来执行此操作——无论鼠标在哪里,都可以读取像素数据,如果它与您的线条颜色相同,则用户点击该线条。但是,这会产生很多假设,例如画布上的所有内容都以不同的纯色呈现。然而,这是可能的,因为一个常见的技巧是以不同的纯色将所有内容渲染到屏幕外的画布上。然后,当用户单击某物时,您可以通过读取该像素的颜色并将其映射回原始对象来准确地知道它是什么。

      但这并不是你所要求的:)

      您不想知道用户是否点击了一行,因为他们几乎永远不会。一条线无限细,所以除非它完全水平或完全垂直,否则他们永远不会点击它。相反,您想要的是查看鼠标与线的距离。 Kolink 刚刚回答了那部分,所以我会在这里停下来:)

      【讨论】:

      • 谢谢 - 我应该考虑使用屏幕外画布来完成我正在做的事情,但我目前还没有这样做。
      猜你喜欢
      • 2011-04-18
      • 1970-01-01
      • 1970-01-01
      • 2014-01-20
      • 2011-04-19
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      相关资源
      最近更新 更多