【问题标题】:Finding element nearest to clicked point查找离点击点最近的元素
【发布时间】:2013-10-19 06:29:32
【问题描述】:

在这里需要一些帮助。我是一名 UI 设计师,不擅长进行实验性 Web 表单设计的数字,我需要知道哪个输入元素最接近网页上的点击点。我知道如何用点做最近邻,但输入元素是矩形而不是点,所以我被卡住了。

我正在使用 jQuery。我只需要这个小算法的帮助。一旦我完成了我的实验,我会向你们展示我在做什么。

更新

我想过它是如何工作的。看这张图:

每个矩形有 8 个点(或者更确切地说是 4 个点和 4 条线),这些点很重要。只有 x 值对水平点有意义(红点),只有 y 值对垂直点有意义(绿点)。 x 和 y 对角点都很重要。

橙色十字是要测量的点——在我的用例中是鼠标点击。浅紫色线是橙色十字与可能最近的点之间的距离。

所以……对于任何给定的橙色十字,遍历每个矩形的 8 个点中的每一个,以找到每个矩形最接近橙色十字的边或角。具有最低值的矩形是最近的。

我可以将其概念化和可视化,但无法将其放入代码中。帮助!

【问题讨论】:

  • 在最近邻算法中使用代表矩形的 4 个点。或者使用矩形的中心点 cx = (left + width)/2, cy = (top + height)/2。
  • 有没有机会在 jsfiddle.net 中发布一些代码或做一些事情?否则这都是假设性的......
  • 添加了一个插图来解释问题以及如何解决它。

标签: javascript jquery algorithm math nearest-neighbor


【解决方案1】:

你的算法是正确的。由于您需要代码方面的帮助,而不是算法方面的帮助,因此这里是代码:

这可能不是最有效的。但它有效。

// Define the click
var click = Array(-1, -2); // coodinates in x,y

// Define the buttons
// Assuming buttons do not overlap
var button0 = Array(
    Array(0, 0), // bottom-left point (assuming x is horizontal and y is vertical)
    Array(6, 6) // upper-right point
);

var button1 = Array(
    Array(10, 11),
    Array(17, 15)
);

var button2 = Array(
    Array(-8, -5),
    Array(-3, -1)
);

// Which button to trigger for a click
i = which(click, Array(button0, button1, button2));
alert(i);


function which(click, buttons){
    // Check if click is inside any of the buttons
    for (i in buttons){
        var button = buttons[i];
        var bl = button[0];
        var tr = button[1];

        if ( (click[0] >= bl[0] && click[0] <= tr[0]) &&
             (click[1] >= bl[1] && click[1] <= tr[1]) ){
            return i;
        }
    }

    // Now calculate distances
    var distances = Array();

    for (i in buttons){
        var button = buttons[i];
        var bl = button[0];
        var tr = button[1];

        if ( (click[0] >= bl[0] && click[0] <= tr[0])) {
            distances[i] = Math.min( Math.abs(click[1]-bl[1]), Math.abs(click[1]-tr[1]) );
        }
        else if ( (click[1] >= bl[1] && click[1] <= tr[1])) {
            distances[i] = Math.min( Math.abs(click[0]-bl[0]), Math.abs(click[0]-tr[0]) );
        }
        else{
            distances[i] =  Math.sqrt(
                                (Math.pow(Math.min( Math.abs(click[0]-bl[0]), Math.abs(click[0]-tr[0]) ), 2)) +
                                (Math.pow(Math.min( Math.abs(click[1]-bl[1]), Math.abs(click[1]-tr[1]) ), 2))
                            );
        }
    }

    var min_id = 0;
    for (j in distances){
        if (distances[j] < distances[min_id]){
            min_id = j;
        }
    }

    return min_id;
}

【讨论】:

  • 太棒了。正是我需要的。如何使代码适应任何宽度和高度?
  • 它可以适应任何宽度和高度。您只需在 JavaScript 的顶部定义按钮的尺寸和点击的坐标。
【解决方案2】:

添加相对较新的elementFromPoint() API 让我们可以采用另一种可能更轻松的方法:我们可以围绕鼠标光标进行测试,在更大的圆圈中进行,直到找到最近的元素。

我在这里整理了一个快速的非生产示例:http://jsfiddle.net/yRhhs/(Chrome/Safari 仅由于使用了 webkitMatchesSelector)。由于在可视化算法中使用了点,因此性能可能会滞后。

除了灯光性能优化和事件绑定之外,代码的核心是这一点:

function hitTest(x, y){
    var element, i = 0;
    while (!element){
        i = i + 7; // Or some other threshold.

        if (i > 250){ // We do want some safety belts on our while loop.
            break;
        }

        var increment = i/Math.sqrt(2);
        var points = [
            [x-increment, y-increment], [x+increment, y-increment],
            [x+increment, y+increment], [x-increment, y+increment]
        ];

        // Pop additional points onto the stack as the value of i gets larger.
        // ...

        // Perhaps prematurely optimized: we're using Array.prototype.some to bail-out
        // early once we've found a valid hit target.
        points.some(function(coordinates){
            var hit = document.elementFromPoint.apply(document, coordinates); 
            // isValidHit() could simply be a method that sees whether the current
            // element matches the kinds of elements we'd like to see.
            if (isValidHit(hit)){
                element = hit;
                return true;
            }
       });
}

【讨论】:

    【解决方案3】:

    您可以查找所有矩形中最近的角点。这在大多数情况下都有效,快速且易于实施。只要您的矩形在规则网格上对齐,此方法就会为您提供最近的矩形。

    【讨论】:

      【解决方案4】:

      我这样做的方式不是数字,而是逻辑。

      我假设你想得到这样的结果,“如果 x 是最近的元素,那么当我点击其他地方时做一些事情然后对 x 做一些事情”

      如果您要处理的每个元素都位于简单的&lt;div&gt; 容器中,这些容器比您要处理的元素大,但不大于它所包含的对象和下一个最近的对象之间的一半,您就可以这样做目的。实际上是一个网格。

      给所有容器同一个类。

      然后你可以说,“如果点击 y,就对 x 做点什么”,你就已经知道每个容器中有哪个元素了。

      我会写代码,但我要离开工作......

      【讨论】:

        【解决方案5】:

        如果要求二维网格上两点之间的距离,可以使用以下公式:

        (对于二维点 A 和 B)

        距离X = A.x - B.x

        距离Y = A.y - B.y

        totalDistance = squareRoot ((distX * distX) + (distY * distY))

        一旦您可以检查两点之间的距离,您就可以很容易地找出您的鼠标点击的矩形角最近。您可以做很多事情来优化您的预期算法,但这应该会给您一个良好的开端。

        【讨论】:

          【解决方案6】:

          大声笑,问题是你为什么要考虑形状? 你的问题真的是“如果我点击一个坐标,找到我点击的最近的节点/点”,这是一个遍历各个节点并计算距离的问题。

          如果X相同,使用y差

          如果y相同,使用x差

          否则使用假设

          一旦你找到最近的点,你就可以得到父形状吗? 这将起作用,因为您正在尝试捕捉到最近的点。所以它甚至可以处理像星星这样的奇特形状。

          【讨论】:

            猜你喜欢
            • 2018-06-25
            • 2018-02-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多