Make it so getMousePosition does not report incorrect position when borders are used in containing elements, by replacing the pagePosition method with a new one and attaching map events to the internal viewport div instead of the user provided map div. r=erilem,tschaub (closes #2247)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@10871 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2010-11-05 12:44:38 +00:00
parent e40bb1f10d
commit a59266325b
6 changed files with 261 additions and 38 deletions

View File

@@ -1336,51 +1336,142 @@ OpenLayers.Util.safeStopPropagation = function(evt) {
/**
* Function: pagePositon
* Calculates the position of an element on the page.
* Calculates the position of an element on the page (see
* http://code.google.com/p/doctype/wiki/ArticlePageOffset)
*
* OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
* Copyright (c) 2006, Yahoo! Inc.
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or
* without modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Yahoo! Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission of Yahoo! Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Parameters:
* forElement - {DOMElement}
*
* Returns:
* {Array} two item array, L value then T value.
* {Array} two item array, Left value then Top value.
*/
OpenLayers.Util.pagePosition = function(forElement) {
var valueT = 0, valueL = 0;
OpenLayers.Util.pagePosition = function(forElement) {
// NOTE: If element is hidden (display none or disconnected or any the
// ancestors are hidden) we get (0,0) by default but we still do the
// accumulation of scroll position.
var element = forElement;
var child = forElement;
while(element) {
var pos = [0, 0];
var viewportElement = OpenLayers.Util.getViewportElement();
if (!forElement || forElement == window || forElement == viewportElement) {
// viewport is always at 0,0 as that defined the coordinate system for
// this function - this avoids special case checks in the code below
return pos;
}
if(element == document.body) {
if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
break;
// Gecko browsers normally use getBoxObjectFor to calculate the position.
// When invoked for an element with an implicit absolute position though it
// can be off by one. Therefore the recursive implementation is used in
// those (relatively rare) cases.
var BUGGY_GECKO_BOX_OBJECT =
OpenLayers.IS_GECKO && document.getBoxObjectFor &&
OpenLayers.Element.getStyle(forElement, 'position') == 'absolute' &&
(forElement.style.top == '' || forElement.style.left == '');
var parent = null;
var box;
if (forElement.getBoundingClientRect) { // IE
box = forElement.getBoundingClientRect();
var scrollTop = viewportElement.scrollTop;
var scrollLeft = viewportElement.scrollLeft;
pos[0] = box.left + scrollLeft;
pos[1] = box.top + scrollTop;
} else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko
// Gecko ignores the scroll values for ancestors, up to 1.9. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
// https://bugzilla.mozilla.org/show_bug.cgi?id=330619
box = document.getBoxObjectFor(forElement);
var vpBox = document.getBoxObjectFor(viewportElement);
pos[0] = box.screenX - vpBox.screenX;
pos[1] = box.screenY - vpBox.screenY;
} else { // safari/opera
pos[0] = forElement.offsetLeft;
pos[1] = forElement.offsetTop;
parent = forElement.offsetParent;
if (parent != forElement) {
while (parent) {
pos[0] += parent.offsetLeft;
pos[1] += parent.offsetTop;
parent = parent.offsetParent;
}
}
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
child = element;
try {
// wrapping this in a try/catch because IE chokes on the offsetParent
element = element.offsetParent;
} catch(e) {
OpenLayers.Console.error(OpenLayers.i18n(
"pagePositionFailed",{'elemId':element.id}));
break;
var browser = OpenLayers.BROWSER_NAME;
// opera & (safari absolute) incorrectly account for body offsetTop
if (browser == "opera" || (browser == "safari" &&
OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
pos[1] -= document.body.offsetTop;
}
// accumulate the scroll positions for everything but the body element
parent = forElement.offsetParent;
while (parent && parent != document.body) {
pos[0] -= parent.scrollLeft;
// see https://bugs.opera.com/show_bug.cgi?id=249965
if (browser != "opera" || parent.tagName != 'TR') {
pos[1] -= parent.scrollTop;
}
parent = parent.offsetParent;
}
}
element = forElement;
while(element) {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
element = element.parentNode;
}
return [valueL, valueT];
return pos;
};
/**
* Function: getViewportElement
* Returns die viewport element of the document. The viewport element is
* usually document.documentElement, except in IE,where it is either
* document.body or document.documentElement, depending on the document's
* compatibility mode (see
* http://code.google.com/p/doctype/wiki/ArticleClientViewportElement)
*/
OpenLayers.Util.getViewportElement = function() {
var viewportElement = arguments.callee.viewportElement;
if (viewportElement == undefined) {
viewportElement = (OpenLayers.BROWSER_NAME == "msie" &&
document.compatMode != 'CSS1Compat') ? document.body :
document.documentElement;
arguments.callee.viewportElement = viewportElement;
}
return viewportElement;
};
/**
* Function: isEquivalentUrl