Search code examples
javascriptjqueryalgorithmmathnearest-neighbor

Finding element nearest to clicked point


Need some help here. I'm a UI designer who isn't good at numbers doing an experimental web form design and I need to know which input element is closest to a clicked point on a web page. I know how to do nearest neighbor with points but the input elements are rectangles not points so I'm stuck.

I'm using jQuery. I just need help with this little algo. Once I'm done with my experiment I'll show you guys what I'm doing.

UPDATE

I thought about how it can work. Look at this diagram:

Nearest

Each rectangle has 8 points (or rather 4 points and 4 lines) which are significant. Only the x value is significant for horizontal points (red dot) and only the y value is significant for vertical points (green dot). Both x and y are significant for the corners.

Orange crosses are the points to be measured against – mouse clicks in my use case. The light purple lines are the distances between the orange cross and it's possible nearest point.

So… for any given orange cross, loop through each of the 8 points n every rectangle to find the nearest edge or corner closest of each rectangle to the orange cross. The rectangle with the lowest value is the nearest one.

I can conceptualize and visualize it but can't put it into code. Help!


Solution

  • Your algorithm is correct. Since you need help in code, and not in the algorithm, here's the code:

    It may not be the most efficient. But it works.

    // 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;
    }