4

假设我在 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. 如何扩展它以查找鼠标按下事件是否发生在线附近

4

3 回答 3

8

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

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

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

图表
(来源:adamhaskell.net

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

于 2013-01-17T04:14:07.767 回答
6

这是取自维基百科文章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);
    }

你的线定义为矩形。希望这可以帮助。

于 2014-04-30T20:45:06.763 回答
1

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

但这不完全是你要求的:)

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

于 2013-01-17T04:14:56.940 回答