1

I've been coding a bit of Javascript to place a ducky randomly on this page.

I wanted to make it hide on the side of objects (like the posts), but I ended up having to hardcode quite a bit of it, since I couldn't get a way to properly retrieve the real position of relative objects with Chrome. I read quite a few things about it, and used the recursive offsetParent way, but didn't get any good results.

The last bit of code I tried was this:

 var getPost = function (obj) {
    var pos = {'x':0,'y':0};
    if(obj.offsetParent) {
        while(1) {
          pos.x += obj.offsetLeft;
          pos.y += obj.offsetTop;
          if(!obj.offsetParent) {
            break;
          }
          obj = obj.offsetParent;
        }
    } else if(obj.x) {
        pos.x += obj.x;
        pos.y += obj.y;
    }
    return pos;
  }

This code doesn't work on Chrome, except on objects with an absolute position (set with CSS).

Is there a good, cross-browser way to achieve this?

raphink
  • 3,625
  • 1
  • 28
  • 39

3 Answers3

1

I had a case where I was working with mouse positions and objects as well not so long ago because I needed some drag and drop. So these are the two methods I came up with:

/**
 * Calculates the mouse x and y position from the mouse move event fired by the document
 * 
 * @param event
 *            the mouse move event fired by the document
 * 
 * @return the mouse coordinates object with two variables x and y
 */
function mouseCoords(ev) {
  var event = ev;

  // IE does not pass the event object
  if (event == null)
    event = window.event;

  try {

    // normal style
    if (event.pageX) {
      return {
          x : event.pageX,
          y : event.pageY
      };
    }
    // IE style
    else {
      return {
          x : event.clientX + document.body.scrollLeft - document.body.clientLeft,
          y : event.clientY + document.body.scrollTop - document.body.clientTop
      };
    }

  } catch(ex) {

    // IE style
    return {
        x : event.clientX + document.body.scrollLeft - document.body.clientLeft,
        y : event.clientY + document.body.scrollTop - document.body.clientTop
    };
  }
}

/**
 * Calculates an object with the x and y coordinates of the given object
 * 
 * @param object
 *            the object of which the coordinates to be calculated
 * 
 * @return an object with x and y coordinates
 */
function getObjectPosition(object) {
  var left = 0;
  var top = 0;

  while (object.offsetParent) {

    left += object.offsetLeft;
    top += object.offsetTop;

    object = object.offsetParent;
  }

  left += object.offsetLeft;
  top += object.offsetTop;

  return {
      x : left,
      y : top
  };
}

I hope this can help you. This works for me in IE, Firefox and Chrome.

eitch
  • 317
  • 2
  • 10
  • This is pretty much the same I'm currently doing. My problem seems to be that offsetParent fails at some point, so this function (or the one I was using before) returns NaN for the elements I'm using it on. – raphink Sep 18 '10 at 19:13
1

Alright, my problem was somewhere else. This is what I was doing to call the function:

var allPosts = document.getElementsByClassName('post-outer');

for (post in allPosts) {
   console.log('Post has position '+getPos(post));
}

You can tell I'm not so used to Javascript's recursive behavior in the for loop, so the following code actually fixes my issue:

var allPosts = document.getElementsByClassName('post-outer');

for (var i=0, len=allPosts.length; i<len; ++i ){
  console.log('Post position is '+getPos(allPosts[i]).y);
}

Thanks all for your help :-)

raphink
  • 3,625
  • 1
  • 28
  • 39
  • The Javascript 'in' keyword doesn't work like you used it in your first example. Change `console.log('Post has position '+getPos(post));` to `console.log('Post has position '+getPos(allPosts[post]));`. The 'in' keyword iterates through each _key_ on the object, rather than the values. That is why the second loop works and the first doesn't. Yep, it's pretty silly. Check out [Underscore JS](http://documentcloud.github.com/underscore/) for a lightweight solution to Javascript silliness in general. – Brandon Oct 12 '11 at 20:37
0

That does not work with absolute positioning because it does not factor in top and left (among other things).

I was going to rip out that part of code from jQuery and post it here, but it is too rooted. So I just have to recommend using jQuery! To do so, just have this in the markup (before any other script tags)...

<script type="text/javascript"
 src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

Once you have that referenced, you can get the position of an element so easily...

$(function() {
  var pos = $(".className").position();
  alert(pos.top + "\n" + pos.left);
});
Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • This looks like a nice solution, unfortunately, I need to work with several elements that match a class, so I use getElementsByClassName and the elements returned do not heriate the position() method. – raphink Sep 18 '10 at 19:09