javascriptjquerygridsnapping

Finding the closest grid coordinate to the mouse position with javascript/jQuery


What I'm trying to do is make a grid of invisible coordinates on the page equally spaced. I then want a <div> to be placed at whatever grid coordinate is closest to the pointer when onclick is triggered. Here's the rough idea:

alt text

I have the tracking of the mouse coordinates and the placing of the <div> worked out fine. What I'm stuck with is how to approach the problem of the grid of coordinates.

First of all, should I have all my coordinates in an array which I then compare my onclick coordinate to?

Or seeing as my grid coordinates follow a rule, could I do something like finding out which coordinate that is a multiple of whatever my spacing is is closest to the onclick coordinate?

And then, where do I start with working out which grid point coordinate is closest? What's the best way of going about it?

Thanks!


Solution

  • I was initially writing an answer similar to bobince's, but he got there before me. I like that way of doing it, but his version has got some floors (though it's still a very good answer).

    I presume that what you want is a HTML-less grid (that is, without markup like a table), which bobince supplies a solution for. In that case, the code may be optimised significantly for cross browser compatibility, readability, errors and speed.

    So, I suggest the code should be more like this:

    #canvas { position: relative; width: 100px; height: 100px; border: solid red 1px; }
    #nearest { position: absolute; width: 10px; height: 10px; background: yellow; }
    
    <div id="canvas"><div id="nearest"></div></div>
    
    var
        canvasOffset = $("div#canvas").offset(),
        // Assuming that the space between the points is 10 pixels. Correct this if necessary.
        cellSpacing = 10;
    
    $("div#canvas").mousemove(function(event) {
        event = event || window.event;
        $("div#nearest").css({
            top: Math.round((mouseCoordinate(event, "X") - canvasOffset.left) / cellSpacing) * cellSpacing + "px",
            left: Math.round((mouseCoordinate(event, "Y") - canvasOffset.top) / cellSpacing) * cellSpacing + "px"
        });
    });
    
    // Returns the one half of the current mouse coordinates relative to the browser window.
    // Assumes the axis parameter to be uppercase: Either "X" or "Y".
    function mouseCoordinate(event, axis) {
        var property = (axis == "X") ? "scrollLeft" : "scrollTop";
        if (event.pageX) {
            return event["page"+axis];
        } else {
            return event["client"+axis] + (document.documentElement[property] ? document.documentElement[property] : document.body[property]);;
        }
    };
    

    The mouseCoordinate() function is a boiled down version of these two functions:

    function mouseAxisX(event) {
        if (event.pageX) {
            return event.pageX;
        } else if (event.clientX) {
            return event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
        }
    };
    
    function mouseAxisY(event) {
        if (event.pageY) {
            return event.pageY;
        } else if (event.clientY) {
            return event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
        }
    };
    

    I really like the idea of your project, perhaps I'll make something similar myself :D