Friday, February 4, 2011

Getting DIV id based on x & y position

The problem I'm trying to solve is "What's at this position?"

It's fairly trivial to get the x/y position (offset) of a DIV, but what about the reverse? How do I get the id of a DIV (or any element) given an x/y position?

  • Use a JQuery selector to filter the list of all DIVs for one that matches your position criteria?

    From Graphain
  • The JQuery selector is pretty useful, but (unless I missed something in the docs) there really aren't any selectors that will do this. I can't filter down based on any other criteria because all I have to work with is an x and y position.

    From Allan
  • Create a mouse event listener, then trigger a mouse event at that location. This should give you the entire stack of elements at that location.

    Or, look at the source of Firebug.

  • These links might be useful: http://brandonaaron.net/docs/dimensions/ http://osdir.com/ml/lang.javascript.jquery/2006-10/msg00242.html

    From Graphain
  • this might be a little too processor intensive but going over the whole list of div elements on a page, finding their positions and sizes then testing if they're under the mouse. i don't think i'd want to do that to a browser though.

    From John Boker
  • Thanks Graphain. I wish it was that simple -- I already know how to get the position of a DIV - this is a little more tricky.

    Nick and John - Unfortunately, I can't use the mouse position.

    I'm thinking that the solution involves creating some logic that takes in the position, does some math, and outputs the DIV id. Looks like there's no easy answer.

    Graphain : Yeah, I think it is going to be like that. Especially for div.contains() type situations.
    From Allan
  • One option is to build an array of "div-dimension" objects. (Not to be confused with the divs themselves... IE7 perf is frustrating when you read dimensions off of object.)

    These objects consist of a pointer to the div, their dimensions (four points... say top, left, bottom, and right), and possibly a dirty bit. (Dirty bit is only really needed if the sizes change.

    You could then iterate through the array and check dimensions. It requires O(n) to do that on each mouse move. You might be able to do slightly better with a binary search style approach... maybe.

    If you do a binary search style approach, one way is to store 4 arrays. Each with a single point of the dimension, and then binary search on all four. O(4logn) = O(logn).

    I'm not saying I recommend any of these, but they MIGHT work.

  • If all you have is the X and Y position, (and you can't track mouse movement like you mentioned) then you will have to traverse the DOM, looping through every DIV. For each DIV you will need to compare its X and Y coordinates against those you have. This is an expensive operation, but it is the only way. I suggest you might be better off rethinking your problem instead of coming up with a solution for it.

    From hal10001
  • You might find it's more efficient to traverse the DOM tree once when the page is loaded, get all elements' positions and sizes, and store them in an array/hash/etc. If you design the data structure well, you should be able to find an element at the given coordinates fairly quickly when you need it later.

    Consider how often you will need to detect an element, and compare that to how often the elements on the page will change. You would be balancing the number of times you have to re-compute all the element locations (an expensive computation) against the number of times you'd actually use the computed information (relatively cheap, I hope).

    From jonblock
  • I think what John is saying is that you can use document.createEvent() to simulate a mousemove at the location you want. If you capture that event, by adding an eventlistener to the body, you can look at the event.target and see what element was at that position. I'm unsure as to what degree IE supports this method, maybe someone else knows?

    http://developer.mozilla.org/en/DOM/document.createEvent

    Update: Here's a jquery plugin that simulates events:

    http://jquery-ui.googlecode.com/svn/trunk/tests/simulate/jquery.simulate.js

  • function getDivByXY(x,y) {
       var alldivs = document.getElementsByTagName('div');
    
       var d;
    
       for(d = 0; d < alldivs.length; d++) {
          if((alldivs[d].offsetLeft == x) && (alldivs[d].offsetTop == y)) {
             return alldivs[d];
          }
       }
    
       return false;
    
    }
    
  • Unfortunately, triggering a manufactured/simulated mouse event won't work, since when you dispatch it, you have to provide a target element. Since that element is the one you're trying to figure out, all you could do is dispatch it on the body, as if it had already bubbled.

    You really are left to do it on your own, that is manually walk through the elements you're interested in, and compare their position/size/zIndex to your x/y point and see if they overlap. Except in IE and more recently FF3, where you can use

    var el = document.elementFromPoint(x, y);
    

    See

    http://developer.mozilla.org/En/DOM:document.elementFromPoint

    http://msdn.microsoft.com/en-us/library/ms536417(VS.85).aspx

    From rdworth

0 comments:

Post a Comment