views:

245

answers:

3

Hi guys

I need to calculate the position, height and width of every anchored link in my page. I know how to find the x,y coords, but I have a problem with the height and width. The problem appears when the link has children inside (images, divs etc), so heightOffset and widthOffset won't work. Is there a way to do this without going on all the children and calculating their sizes?

EDIT:

Here is some code to demonstrate what I mean (the press function is called whenever the mouse is being pressed):

function findPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    return [curleft,curtop];
}

function getHeight(elem) {

          if (elem.style.pixelHeight) {
             return elem.style.pixelHeight;
          } else {
             return elem.offsetHeight;
          }
    }
function getWidth(elem) {

    if (elem.style.pixelWidth) {
       return elem.style.pixelWidth;
    } else {
       return elem.offsetWidth;
    }
}

function press(e)
{


      x= e.pageX;
      y= e.pageY;

    window.alert(x+","+y);


            var links = document.getElementsByTagName('a');
            for (i = 0; i < links.length; i++){
                var pos = findPos(links[i]);
                window.alert(x+","+y+" "+pos[0]+" " + pos[1] + " "+links[i].offsetWidth+ " "+links[i].offsetHeight);
                if (x >= pos[0] && x <= pos[0] + getWidth(links[i]) && y >= pos[1] && y <= pos[1] + getHeight(links[i])){
                    window.alert(links[i].href);
                    i = links.length;
                }
            }


}

When I encounter a link with an image for instance it doesn't return me the right size.

Thanks

A: 

The correct properties are offsetHeight (not heightOffset) and offsetWidth (not widthOffset).
Those properties should correctly return the sizes you're after, because the children would expand the elements to fit, assuming overflow is set to visible. There's no need to calculate the sizes of the children in any situation.

offsetHeight and offsetWidth aren't part of any standard but most browsers seem to have them implemented anyway.

Since you're having problems with Safari and offsetHeight, maybe you could try the getClientRects() method:

http://www.quirksmode.org/dom/tests/rectangles.html

var dims   = links[i].getClientRects()[0];
var width  = dims.right - dims.left;
var height = dims.bottom - dims.top;

Can't say I've ever used getClientRects(), however. It sounds like the results may be closer to clientWidth and clientHeight.

FURTHER EDIT
I figured out a workaround. The following does not work:

<a href="#">
  <img onclick="press(event);" src="http://sstatic.net/so/img/logo.png" alt="" />
  <!-- onclick handler alerts with size 250x15 -->
</a>

But wrapping a <span> tag around the <img> tag, like so:

<a href="#"><span>
  <img onclick="press(event);" src="http://sstatic.net/so/img/logo.png" />
  <!-- onclick handler alerts with size 250x61 -->
</span></a>

Fixes the problem. At least, it does in Chrome but like I said before Chrome and Safari share the WebKit rendering engine, so it should work for Safari too.

Andy E
I ran some tests and I don't think what you say is true. I also attached some code - maybe there is something wrong with it.
Alex1987
@Alex1987: Which browsers have you tested it in? It works fine in IE6-8 but Chrome returns an incorrect value for offsetHeight. I don't have Firefox or Opera installed on this machine though so I can't test in those. I suspect this is a bug in Chrome, though. Read https://developer.mozilla.org/en/Determining_the_dimensions_of_elements for a detailed explanation of offset dimensions.
Andy E
Safari and mobileSafari (on the iphone) - also return incorrect values for offsetHeight!!
Alex1987
Safari uses the same rendering engine as Chrome (WebKit)
Andy E
Have you tried the `getClientRects()` method?
Andy E
I'll try this later. Thanks.
Alex1987
Tested it and gives me the same wrong results
Alex1987
@Alex1987: I figured out a workaround. Wrap a `<span>` tag around the `<img>` tag and it works - see my updated answer.
Andy E
+1  A: 

offsetWidth/Height do very much work on links that contain images, as long as you haven't done anything weird like overflowing or positioning the images or other child content so that they fall out of the content area of their parent.

Your code isn't using offsetHeight on IE, it's using pixelHeight, which doesn't do what perhaps you think it does. Stick with offsetHeight.

Conversely, you are using event.pageX/Y, which is a non-standard extension IE doesn't have. Sadly the only reliable way to get page-relative co-ordinates from an event is to use clientX/Y and adjust for viewport scrolling.

I don't really know why you are going to the effort of enumerating link positions when for a mouse click/down event you can quite reliably get the element that was clicked on using event.target/srcElement. In fact this is the only reliable way to do it. Consider a link that has split over two text lines. Now what you've got is a non-rectangular region; you can't test whether a particular mouse position lies within that area using a simple x and y range test.

bobince
actually I don't care much about IE, since I'm writing an iphone app. I am attempting to detect a tap on a link (I don't want to use the touchstart event) by the coordinates.
Alex1987
@bobince, I tested his code with a very simple line of html `<a href="#"><img onclick="press(event);" src="http://sstatic.net/so/img/logo.png" /></a>` and it returns 15 as the offsetHeight - could this be a buggy implementation of offsetHeight in WebKit?
Andy E
@Andy E: that will be the correct value for the line-height; remember that both `a` and `img` are inline elements by default. If the image is taller than the line, it will overflow in the visual rendering, but the `a` element itself doesn't stretch to accommodate it. Adding `overflow:hidden;` to the `a` element will show you what I mean.
NickFitz
You could always make the `a` a block or inline-block if you want it to encompass its inline content. However, again, all this should be completely unnecessary; just look at the `event.target` element.
bobince
@NickFitz: I figured it was probably the line-height of the `a` element. What was weird was that putting the img in a span tag fixed the problem, so the a element would stretch to the size of a span tag but not to the size of an img tag.
Andy E
A: 

You should not use the values in elem.style.* to determine the size of an element. These values are CSS styles and aren't reliable. Use only offsetWidth and offsetHeight.

To get the position of an element, use the answers to this question: http://stackoverflow.com/questions/442404/dyanamically-reterive-html-element-x-y-position-with-javascript

Aaron Digulla