[OpenLayers-Commits] r10871 - in trunk/openlayers: build lib/OpenLayers lib/OpenLayers/Handler tests/manual

commits-20090109 at openlayers.org commits-20090109 at openlayers.org
Fri Nov 5 08:44:38 EDT 2010


Author: ahocevar
Date: 2010-11-05 05:44:38 -0700 (Fri, 05 Nov 2010)
New Revision: 10871

Added:
   trunk/openlayers/tests/manual/page-position.html
Modified:
   trunk/openlayers/build/license.txt
   trunk/openlayers/lib/OpenLayers/Events.js
   trunk/openlayers/lib/OpenLayers/Handler/Drag.js
   trunk/openlayers/lib/OpenLayers/Map.js
   trunk/openlayers/lib/OpenLayers/Util.js
Log:
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)


Modified: trunk/openlayers/build/license.txt
===================================================================
--- trunk/openlayers/build/license.txt	2010-11-05 07:49:12 UTC (rev 10870)
+++ trunk/openlayers/build/license.txt	2010-11-05 12:44:38 UTC (rev 10871)
@@ -90,3 +90,36 @@
  * issues. Applications that use the code below will continue to work seamlessly
  * 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.
+ */
\ No newline at end of file

Modified: trunk/openlayers/lib/OpenLayers/Events.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Events.js	2010-11-05 07:49:12 UTC (rev 10870)
+++ trunk/openlayers/lib/OpenLayers/Events.js	2010-11-05 12:44:38 UTC (rev 10871)
@@ -823,11 +823,10 @@
         }
         
         if (!this.element.scrolls) {
+            var viewportElement = OpenLayers.Util.getViewportElement();
             this.element.scrolls = [
-                (document.documentElement.scrollLeft
-                         || document.body.scrollLeft),
-                (document.documentElement.scrollTop
-                         || document.body.scrollTop)
+                viewportElement.scrollLeft,
+                viewportElement.scrollTop
             ];
         }
 
@@ -840,8 +839,6 @@
         
         if (!this.element.offsets) {
             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(
             (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]

Modified: trunk/openlayers/lib/OpenLayers/Handler/Drag.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Handler/Drag.js	2010-11-05 07:49:12 UTC (rev 10870)
+++ trunk/openlayers/lib/OpenLayers/Handler/Drag.js	2010-11-05 12:44:38 UTC (rev 10871)
@@ -397,7 +397,7 @@
      * evt - {Object}
      */
     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.y -= pos[1];
     },

Modified: trunk/openlayers/lib/OpenLayers/Map.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Map.js	2010-11-05 07:49:12 UTC (rev 10870)
+++ trunk/openlayers/lib/OpenLayers/Map.js	2010-11-05 12:44:38 UTC (rev 10871)
@@ -513,7 +513,7 @@
         this.viewPortDiv.appendChild(this.layerContainerDiv);
 
         this.events = new OpenLayers.Events(this, 
-                                            this.div, 
+                                            this.viewPortDiv, 
                                             this.EVENT_TYPES, 
                                             this.fallThrough, 
                                             {includeXY: true});
@@ -610,7 +610,6 @@
     render: function(div) {
         this.div = OpenLayers.Util.getElement(div);
         OpenLayers.Element.addClass(this.div, 'olMap');
-        this.events.attachToElement(this.div);
         this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
         this.div.appendChild(this.viewPortDiv);
         this.updateSize();

Modified: trunk/openlayers/lib/OpenLayers/Util.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Util.js	2010-11-05 07:49:12 UTC (rev 10870)
+++ trunk/openlayers/lib/OpenLayers/Util.js	2010-11-05 12:44:38 UTC (rev 10871)
@@ -1336,51 +1336,142 @@
 
 /**
  * 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;
         }
-    }
 
-    element = forElement;
-    while(element) {
-        valueT -= element.scrollTop  || 0;
-        valueL -= element.scrollLeft || 0;
-        element = element.parentNode;
+        // 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;
+        }
     }
     
-    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

Added: trunk/openlayers/tests/manual/page-position.html
===================================================================
--- trunk/openlayers/tests/manual/page-position.html	                        (rev 0)
+++ trunk/openlayers/tests/manual/page-position.html	2010-11-05 12:44:38 UTC (rev 10871)
@@ -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>



More information about the Commits mailing list