<< Update ListBox item in Windows Forms | Home | Item dragging in Windows Forms ListBox control >>
EasyQuery at work

Absolute coordinates of DOM element within document

The problem

Sometimes (especially in AJAX projects) it is necessary to get the position of some DOM element in "absolute" coordinates within current document.
For example such "absolute" position is needed if you would like to show some hidden DIV object exactly on the position (or with some offset) of another element. We use this function in our EasyQuery.NET WebForms library to show popup menu under some condition element (you can see an example here).

The solution

Such properties as style.left, style.top or offsetLeft, offsetTop can be used to get (or set) the position of element within its parent. So to get absolute element's position within document we should move upward on element's tree and add the position of all element's parents (except the latest document element).

However it is not quite easy. There are still some problems:

  1. First, we need to take into account possible scrolling in element's parents and decrease our result accordingly.
  2. Second, there are some distinctions in behavior of different browsers (as usual :-( ). For Internet Explorer we always can just subtract scrolling position of the object stored in element's offsetParent prooperty. But for FireFox we also need to take into consideration all parents accessible by parentNode properties.
  3. Finally, we should take into account the border width for some parent elements. Unfortunately this task is not so easy as it can be supposed especially for Internet Explorer browser.

So here is the function we get in result:

var __isIE =  navigator.appVersion.match(/MSIE/);
var __userAgent = navigator.userAgent;
var __isFireFox = __userAgent.match(/firefox/i);
var __isFireFoxOld = __isFireFox && (__userAgent.match(/firefox\/2./i) || __userAgent.match(/firefox\/1./i));
var __isFireFoxNew = __isFireFox && !__isFireFoxOld;


function __parseBorderWidth(width) {
    var res = 0;
    if (typeof(width) == "string" && width != null && width != "" ) {
        var p = width.indexOf("px");
        if (p >= 0) {
            res = parseInt(width.substring(0, p));
        }
        else {
     		//do not know how to calculate other values (such as 0.5em or 0.1cm) correctly now
    		//so just set the width to 1 pixel
            res = 1; 
        }
    }
    return res;
}


//returns border width for some element
function __getBorderWidth(element) {
	var res = new Object();
	res.left = 0; res.top = 0; res.right = 0; res.bottom = 0;
	if (window.getComputedStyle) {
		//for Firefox
		var elStyle = window.getComputedStyle(element, null);
		res.left = parseInt(elStyle.borderLeftWidth.slice(0, -2));  
		res.top = parseInt(elStyle.borderTopWidth.slice(0, -2));  
		res.right = parseInt(elStyle.borderRightWidth.slice(0, -2));  
		res.bottom = parseInt(elStyle.borderBottomWidth.slice(0, -2));  
	}
	else {
		//for other browsers
		res.left = __parseBorderWidth(element.style.borderLeftWidth);
		res.top = __parseBorderWidth(element.style.borderTopWidth);
		res.right = __parseBorderWidth(element.style.borderRightWidth);
		res.bottom = __parseBorderWidth(element.style.borderBottomWidth);
	}
   
	return res;
}

//returns absolute position of some element within document
function getAbsolutePos(element) {
	var res = new Object();
	res.x = 0; res.y = 0;
	if (element !== null) {
		res.x = element.offsetLeft;
		res.y = element.offsetTop;
    	
		var offsetParent = element.offsetParent;
		var parentNode = element.parentNode;
		var borderWidth = null;

		while (offsetParent != null) {
			res.x += offsetParent.offsetLeft;
			res.y += offsetParent.offsetTop;
			
			var parentTagName = offsetParent.tagName.toLowerCase();	

			if ((__isIE && parentTagName != "table") || (__isFireFoxNew && parentTagName == "td")) {		    
				borderWidth = __getBorderWidth(offsetParent);
				res.x += borderWidth.left;
				res.y += borderWidth.top;
			}
		    
			if (offsetParent != document.body && offsetParent != document.documentElement) {
				res.x -= offsetParent.scrollLeft;
				res.y -= offsetParent.scrollTop;
			}

			//next lines are necessary to support FireFox problem with offsetParent
   			if (!__isIE) {
    			while (offsetParent != parentNode && parentNode !== null) {
					res.x -= parentNode.scrollLeft;
					res.y -= parentNode.scrollTop;
					
					if (__isFireFoxOld) {
						borderWidth = _getBorderWidth(parentNode);
						res.x += borderWidth.left;
						res.y += borderWidth.top;
					}
    				parentNode = parentNode.parentNode;
    			}    
			}

   			parentNode = offsetParent.parentNode;
    		offsetParent = offsetParent.offsetParent;
		}
	}
    return res;
}



To use this function just pass your element in function's parameter and get the result object with left and top coordinates stored in x and y properties accordingly:

   
     var pos = getElementAbsolutePos(myElement);  
     window.alert("Element's left: " + pos.x " and top: " + pos.y);  
GetElementAbsolutePos function was tested on all most used browswers:
  • Internet Explorer 6.0 and higher
  • FireFox 2.x and FireFox 3.x.
  • Opera 9.x

We have not tested it on Chrome yet but I do not think there will be some problems.



Re: Absolute coordinates of DOM element within document

Thank you so much for posting this! It was a huge help!

Re: Absolute coordinates of DOM element within document

yes great function! have been looking for it in the net and found it here!! cheers man ;)

Re: Absolute coordinates of DOM element within document

thanks, love cut-and-paste helper functions

Re: Absolute coordinates of DOM element within document

It does not worked on FF3.
Best regards!

Re: Absolute coordinates of DOM element within document

Thanks! That is nice! This saves my time trying to figure out if there is a property for each element in an html document which holds it absolute position. You rock!

Re: Absolute coordinates of DOM element within document

Thanks a lot. It works like a charm. It saved a lot of time for me.

Grate code - spcially for firefox

Thanks for that code, it's really helpful

Re: Absolute coordinates of DOM element within document

Thanks for posting this  function. It is very helpful and saved lot of time.

Element position in Firefox

setting the position needs a unit in firefox .style.left = x + "px"

Element position in Firefox

I agree with you but there is no such assignment in our code ( .style.left = ... )

Re: Absolute coordinates of DOM element within document

The code says

borderWidth = kGetBorderWidth(parentNode);

Is that just a typo and it's supposed to be "__getBorderWidth(...)"?

Re: Absolute coordinates of DOM element within document

Hi,

You are totally right.
I have already fixed this typo in the code.

Re: Absolute coordinates of DOM element within document

Cool. Thanks.

Re: Absolute coordinates of DOM element within document

Works nice for FF and Chrome, but IE7 reports values: -1 for both x and y

Re: Absolute coordinates of DOM element within document

Could you send an example of such page to techsupport@korzh.com?

Add a comment Send a TrackBack