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:
@@ -90,3 +90,36 @@
|
|||||||
* issues. Applications that use the code below will continue to work seamlessly
|
* issues. Applications that use the code below will continue to work seamlessly
|
||||||
* when that happens.
|
* when that happens.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
@@ -823,11 +823,10 @@ OpenLayers.Events = OpenLayers.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.element.scrolls) {
|
if (!this.element.scrolls) {
|
||||||
|
var viewportElement = OpenLayers.Util.getViewportElement();
|
||||||
this.element.scrolls = [
|
this.element.scrolls = [
|
||||||
(document.documentElement.scrollLeft
|
viewportElement.scrollLeft,
|
||||||
|| document.body.scrollLeft),
|
viewportElement.scrollTop
|
||||||
(document.documentElement.scrollTop
|
|
||||||
|| document.body.scrollTop)
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,8 +839,6 @@ OpenLayers.Events = OpenLayers.Class({
|
|||||||
|
|
||||||
if (!this.element.offsets) {
|
if (!this.element.offsets) {
|
||||||
this.element.offsets = OpenLayers.Util.pagePosition(this.element);
|
this.element.offsets = OpenLayers.Util.pagePosition(this.element);
|
||||||
this.element.offsets[0] += this.element.scrolls[0];
|
|
||||||
this.element.offsets[1] += this.element.scrolls[1];
|
|
||||||
}
|
}
|
||||||
return new OpenLayers.Pixel(
|
return new OpenLayers.Pixel(
|
||||||
(evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
|
(evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
|
|||||||
* evt - {Object}
|
* evt - {Object}
|
||||||
*/
|
*/
|
||||||
adjustXY: function(evt) {
|
adjustXY: function(evt) {
|
||||||
var pos = OpenLayers.Util.pagePosition(this.map.div);
|
var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv);
|
||||||
evt.xy.x -= pos[0];
|
evt.xy.x -= pos[0];
|
||||||
evt.xy.y -= pos[1];
|
evt.xy.y -= pos[1];
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ OpenLayers.Map = OpenLayers.Class({
|
|||||||
this.viewPortDiv.appendChild(this.layerContainerDiv);
|
this.viewPortDiv.appendChild(this.layerContainerDiv);
|
||||||
|
|
||||||
this.events = new OpenLayers.Events(this,
|
this.events = new OpenLayers.Events(this,
|
||||||
this.div,
|
this.viewPortDiv,
|
||||||
this.EVENT_TYPES,
|
this.EVENT_TYPES,
|
||||||
this.fallThrough,
|
this.fallThrough,
|
||||||
{includeXY: true});
|
{includeXY: true});
|
||||||
@@ -610,7 +610,6 @@ OpenLayers.Map = OpenLayers.Class({
|
|||||||
render: function(div) {
|
render: function(div) {
|
||||||
this.div = OpenLayers.Util.getElement(div);
|
this.div = OpenLayers.Util.getElement(div);
|
||||||
OpenLayers.Element.addClass(this.div, 'olMap');
|
OpenLayers.Element.addClass(this.div, 'olMap');
|
||||||
this.events.attachToElement(this.div);
|
|
||||||
this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
|
this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
|
||||||
this.div.appendChild(this.viewPortDiv);
|
this.div.appendChild(this.viewPortDiv);
|
||||||
this.updateSize();
|
this.updateSize();
|
||||||
|
|||||||
@@ -1336,51 +1336,142 @@ OpenLayers.Util.safeStopPropagation = function(evt) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function: pagePositon
|
* 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:
|
* Parameters:
|
||||||
* forElement - {DOMElement}
|
* forElement - {DOMElement}
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* {Array} two item array, L value then T value.
|
* {Array} two item array, Left value then Top value.
|
||||||
*/
|
*/
|
||||||
OpenLayers.Util.pagePosition = function(forElement) {
|
OpenLayers.Util.pagePosition = function(forElement) {
|
||||||
var valueT = 0, valueL = 0;
|
// 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 pos = [0, 0];
|
||||||
var child = forElement;
|
var viewportElement = OpenLayers.Util.getViewportElement();
|
||||||
while(element) {
|
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) {
|
// Gecko browsers normally use getBoxObjectFor to calculate the position.
|
||||||
if(OpenLayers.Element.getStyle(child, 'position') == 'absolute') {
|
// When invoked for an element with an implicit absolute position though it
|
||||||
break;
|
// 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;
|
var browser = OpenLayers.BROWSER_NAME;
|
||||||
try {
|
|
||||||
// wrapping this in a try/catch because IE chokes on the offsetParent
|
// opera & (safari absolute) incorrectly account for body offsetTop
|
||||||
element = element.offsetParent;
|
if (browser == "opera" || (browser == "safari" &&
|
||||||
} catch(e) {
|
OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
|
||||||
OpenLayers.Console.error(OpenLayers.i18n(
|
pos[1] -= document.body.offsetTop;
|
||||||
"pagePositionFailed",{'elemId':element.id}));
|
}
|
||||||
break;
|
|
||||||
|
// 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
|
* Function: isEquivalentUrl
|
||||||
|
|||||||
103
tests/manual/page-position.html
Normal file
103
tests/manual/page-position.html
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Page Position Test</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../theme/default/style.css" type="text/css" />
|
||||||
|
<link rel="stylesheet" href="../../examples/style.css" type="text/css" />
|
||||||
|
<style type="text/css">
|
||||||
|
#mapwrap {
|
||||||
|
border: 10px solid red;
|
||||||
|
width: 532px;
|
||||||
|
height: 276px;
|
||||||
|
}
|
||||||
|
#map {
|
||||||
|
position: absolute;
|
||||||
|
border: 10px solid #ccc;
|
||||||
|
width: 512px;
|
||||||
|
height: 256px;
|
||||||
|
}
|
||||||
|
#controlToggle li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
width: 512px;
|
||||||
|
}
|
||||||
|
#scrollspace {
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../../lib/OpenLayers.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var map, drawControls;
|
||||||
|
function init(){
|
||||||
|
map = new OpenLayers.Map('map');
|
||||||
|
|
||||||
|
var wmsLayer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
|
||||||
|
"http://vmap0.tiles.osgeo.org/wms/vmap0?", {layers: 'basic'});
|
||||||
|
|
||||||
|
var lineLayer = new OpenLayers.Layer.Vector("Line Layer");
|
||||||
|
|
||||||
|
map.addLayers([wmsLayer, lineLayer]);
|
||||||
|
map.addControl(new OpenLayers.Control.LayerSwitcher());
|
||||||
|
map.addControl(new OpenLayers.Control.MousePosition());
|
||||||
|
|
||||||
|
drawControl = new OpenLayers.Control.DrawFeature(lineLayer,
|
||||||
|
OpenLayers.Handler.Path);
|
||||||
|
|
||||||
|
map.addControl(drawControl);
|
||||||
|
|
||||||
|
map.setCenter(new OpenLayers.LonLat(0, 0), 3);
|
||||||
|
|
||||||
|
document.getElementById('noneToggle').checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleControl(element) {
|
||||||
|
var control = drawControl;
|
||||||
|
if(element.value == "draw" && element.checked) {
|
||||||
|
control.activate();
|
||||||
|
} else {
|
||||||
|
control.deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body onload="init()">
|
||||||
|
<h1 id="title">OpenLayers Page Position Test</h1>
|
||||||
|
|
||||||
|
<p id="shortdesc">
|
||||||
|
Test if borders and scroll position cause unwanted offsets on the
|
||||||
|
mouse positions reported by map events.
|
||||||
|
</p>
|
||||||
|
<div id="mapwrap">
|
||||||
|
<div id="map"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul id="controlToggle">
|
||||||
|
<li>
|
||||||
|
<input type="radio" name="type" value="none" id="noneToggle"
|
||||||
|
onclick="toggleControl(this);" checked="checked" />
|
||||||
|
<label for="noneToggle">navigate</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="radio" name="type" value="draw" id="lineToggle" onclick="toggleControl(this);" />
|
||||||
|
<label for="lineToggle">draw line</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div id="docs">
|
||||||
|
<p>This map's div has a border and absolute positioning, wrapped
|
||||||
|
by a container which also has a border. The page is also
|
||||||
|
scrollable. Neither the borders nor scrolling the page should
|
||||||
|
result in unwanted offsets on pixel positions reported by map
|
||||||
|
events.</p>
|
||||||
|
<p>With the line drawing control active, click on the map to add a
|
||||||
|
point. The point should be drawn at the exact mouse location.</p>
|
||||||
|
<p>With the navigation control active, shift-drag a zoom rectangle.
|
||||||
|
The rectangle's corner should align exactly with the mouse
|
||||||
|
cursor.</p>
|
||||||
|
<p>Scroll the page and repeat the above tests.</p>
|
||||||
|
<div id="scrollspace"><div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user