/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the 2-clause BSD license. * See license.txt in the OpenLayers distribution or repository for the * full text of the license. */ /** * @requires OpenLayers/BaseTypes.js * @requires OpenLayers/BaseTypes/Bounds.js * @requires OpenLayers/BaseTypes/Element.js * @requires OpenLayers/BaseTypes/LonLat.js * @requires OpenLayers/BaseTypes/Pixel.js * @requires OpenLayers/BaseTypes/Size.js * @requires OpenLayers/Lang.js */ /** * Namespace: Util */ OpenLayers.Util = OpenLayers.Util || {}; /** * Function: getElement * This is the old $() from prototype * * Parameters: * e - {String or DOMElement or Window} * * Returns: * {Array(DOMElement) or DOMElement} */ OpenLayers.Util.getElement = function() { var elements = []; for (var i=0, len=arguments.length; i= 0; i--) { if(array[i] == item) { array.splice(i,1); //break;more than once?? } } return array; }; /** * Function: indexOf * Seems to exist already in FF, but not in MOZ. * * Parameters: * array - {Array} * obj - {*} * * Returns: * {Integer} The index at which the first object was found in the array. * If not found, returns -1. */ OpenLayers.Util.indexOf = function(array, obj) { // use the build-in function if available. if (typeof array.indexOf == "function") { return array.indexOf(obj); } else { for (var i = 0, len = array.length; i < len; i++) { if (array[i] == obj) { return i; } } return -1; } }; /** * Property: dotless * {RegExp} * Compiled regular expression to match dots ("."). This is used for replacing * dots in identifiers. Because object identifiers are frequently used for * DOM element identifiers by the library, we avoid using dots to make for * more sensible CSS selectors. * * TODO: Use a module pattern to avoid bloating the API with stuff like this. */ OpenLayers.Util.dotless = /\./g; /** * Function: modifyDOMElement * * Modifies many properties of a DOM element all at once. Passing in * null to an individual parameter will avoid setting the attribute. * * Parameters: * element - {DOMElement} DOM element to modify. * id - {String} The element id attribute to set. Note that dots (".") will be * replaced with underscore ("_") in setting the element id. * px - {|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * position - {String} The position attribute. eg: absolute, * relative, etc. * border - {String} The style.border attribute. eg: * solid black 2px * overflow - {String} The style.overview attribute. * opacity - {Float} Fractional value (0.0 - 1.0) */ OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, border, overflow, opacity) { if (id) { element.id = id.replace(OpenLayers.Util.dotless, "_"); } if (px) { element.style.left = px.x + "px"; element.style.top = px.y + "px"; } if (sz) { element.style.width = sz.w + "px"; element.style.height = sz.h + "px"; } if (position) { element.style.position = position; } if (border) { element.style.border = border; } if (overflow) { element.style.overflow = overflow; } if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) { element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'; element.style.opacity = opacity; } else if (parseFloat(opacity) == 1.0) { element.style.filter = ''; element.style.opacity = ''; } }; /** * Function: createDiv * Creates a new div and optionally set some standard attributes. * Null may be passed to each parameter if you do not wish to * set a particular attribute. * Note - zIndex is NOT set on the resulting div. * * Parameters: * id - {String} An identifier for this element. If no id is * passed an identifier will be created * automatically. Note that dots (".") will be replaced with * underscore ("_") when generating ids. * px - {|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * imgURL - {String} A url pointing to an image to use as a * background image. * position - {String} The style.position value. eg: absolute, * relative etc. * border - {String} The the style.border value. * eg: 2px solid black * overflow - {String} The style.overflow value. Eg. hidden * opacity - {Float} Fractional value (0.0 - 1.0) * * Returns: * {DOMElement} A DOM Div created with the specified attributes. */ OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position, border, overflow, opacity) { var dom = document.createElement('div'); if (imgURL) { dom.style.backgroundImage = 'url(' + imgURL + ')'; } //set generic properties if (!id) { id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); } if (!position) { position = "absolute"; } OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position, border, overflow, opacity); return dom; }; /** * Function: createImage * Creates an img element with specific attribute values. * * Parameters: * id - {String} The id field for the img. If none assigned one will be * automatically generated. * px - {|Object} The element left and top position, * OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {|Object} The element width and height, * OpenLayers.Size or an object with a * 'w' and 'h' properties. * imgURL - {String} The url to use as the image source. * position - {String} The style.position value. * border - {String} The border to place around the image. * opacity - {Float} Fractional value (0.0 - 1.0) * delayDisplay - {Boolean} If true waits until the image has been * loaded. * * Returns: * {DOMElement} A DOM Image created with the specified attributes. */ OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border, opacity, delayDisplay) { var image = document.createElement("img"); //set generic properties if (!id) { id = OpenLayers.Util.createUniqueID("OpenLayersDiv"); } if (!position) { position = "relative"; } OpenLayers.Util.modifyDOMElement(image, id, px, sz, position, border, null, opacity); if (delayDisplay) { image.style.display = "none"; function display() { image.style.display = ""; OpenLayers.Event.stopObservingElement(image); } OpenLayers.Event.observe(image, "load", display); OpenLayers.Event.observe(image, "error", display); } //set special properties image.style.alt = id; image.galleryImg = "no"; if (imgURL) { image.src = imgURL; } return image; }; /** * Property: IMAGE_RELOAD_ATTEMPTS * {Integer} How many times should we try to reload an image before giving up? * Default is 0 */ OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0; /** * Property: alphaHackNeeded * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. */ OpenLayers.Util.alphaHackNeeded = null; /** * Function: alphaHack * Checks whether it's necessary (and possible) to use the png alpha * hack which allows alpha transparency for png images under Internet * Explorer. * * Returns: * {Boolean} true if the png alpha hack is necessary and possible, false otherwise. */ OpenLayers.Util.alphaHack = function() { if (OpenLayers.Util.alphaHackNeeded == null) { var arVersion = navigator.appVersion.split("MSIE"); var version = parseFloat(arVersion[1]); var filter = false; // IEs4Lin dies when trying to access document.body.filters, because // the property is there, but requires a DLL that can't be provided. This // means that we need to wrap this in a try/catch so that this can // continue. try { filter = !!(document.body.filters); } catch (e) {} OpenLayers.Util.alphaHackNeeded = (filter && (version >= 5.5) && (version < 7)); } return OpenLayers.Util.alphaHackNeeded; }; /** * Function: modifyAlphaImageDiv * * Parameters: * div - {DOMElement} Div containing Alpha-adjusted Image * id - {String} * px - {|Object} OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {|Object} OpenLayers.Size or an object with * a 'w' and 'h' properties. * imgURL - {String} * position - {String} * border - {String} * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" * opacity - {Float} Fractional value (0.0 - 1.0) */ OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, position, border, sizing, opacity) { OpenLayers.Util.modifyDOMElement(div, id, px, sz, position, null, null, opacity); var img = div.childNodes[0]; if (imgURL) { img.src = imgURL; } OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, "relative", border); if (OpenLayers.Util.alphaHack()) { if(div.style.display != "none") { div.style.display = "inline-block"; } if (sizing == null) { sizing = "scale"; } div.style.filter = "progid:DXImageTransform.Microsoft" + ".AlphaImageLoader(src='" + img.src + "', " + "sizingMethod='" + sizing + "')"; if (parseFloat(div.style.opacity) >= 0.0 && parseFloat(div.style.opacity) < 1.0) { div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")"; } img.style.filter = "alpha(opacity=0)"; } }; /** * Function: createAlphaImageDiv * * Parameters: * id - {String} * px - {|Object} OpenLayers.Pixel or an object with * a 'x' and 'y' properties. * sz - {|Object} OpenLayers.Size or an object with * a 'w' and 'h' properties. * imgURL - {String} * position - {String} * border - {String} * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale" * opacity - {Float} Fractional value (0.0 - 1.0) * delayDisplay - {Boolean} If true waits until the image has been * loaded. * * Returns: * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is * needed for transparency in IE, it is added. */ OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL, position, border, sizing, opacity, delayDisplay) { var div = OpenLayers.Util.createDiv(); var img = OpenLayers.Util.createImage(null, null, null, null, null, null, null, delayDisplay); img.className = "olAlphaImg"; div.appendChild(img); OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position, border, sizing, opacity); return div; }; /** * Function: upperCaseObject * Creates a new hashtable and copies over all the keys from the * passed-in object, but storing them under an uppercased * version of the key at which they were stored. * * Parameters: * object - {Object} * * Returns: * {Object} A new Object with all the same keys but uppercased */ OpenLayers.Util.upperCaseObject = function (object) { var uObject = {}; for (var key in object) { uObject[key.toUpperCase()] = object[key]; } return uObject; }; /** * Function: applyDefaults * Takes an object and copies any properties that don't exist from * another properties, by analogy with OpenLayers.Util.extend() from * Prototype.js. * * Parameters: * to - {Object} The destination object. * from - {Object} The source object. Any properties of this object that * are undefined in the to object will be set on the to object. * * Returns: * {Object} A reference to the to object. Note that the to argument is modified * in place and returned by this function. */ OpenLayers.Util.applyDefaults = function (to, from) { to = to || {}; /* * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative * prototype object" when calling hawOwnProperty if the source object is an * instance of window.Event. */ var fromIsEvt = typeof window.Event == "function" && from instanceof window.Event; for (var key in from) { if (to[key] === undefined || (!fromIsEvt && from.hasOwnProperty && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) { to[key] = from[key]; } } /** * IE doesn't include the toString property when iterating over an object's * properties with the for(property in object) syntax. Explicitly check if * the source has its own toString property. */ if(!fromIsEvt && from && from.hasOwnProperty && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) { to.toString = from.toString; } return to; }; /** * Function: getParameterString * * Parameters: * params - {Object} * * Returns: * {String} A concatenation of the properties of an object in * http parameter notation. * (ex. "key1=value1&key2=value2&key3=value3") * If a parameter is actually a list, that parameter will then * be set to a comma-seperated list of values (foo,bar) instead * of being URL escaped (foo%3Abar). */ OpenLayers.Util.getParameterString = function(params) { var paramsArray = []; for (var key in params) { var value = params[key]; if ((value != null) && (typeof value != 'function')) { var encodedValue; if (typeof value == 'object' && value.constructor == Array) { /* value is an array; encode items and separate with "," */ var encodedItemArray = []; var item; for (var itemIndex=0, len=value.length; itemIndex} (or any object with both .lat, .lon properties) * p2 - {} (or any object with both .lat, .lon properties) * * Returns: * {Float} The distance (in km) between the two input points as measured on an * ellipsoid. Note that the input point objects must be in geographic * coordinates (decimal degrees) and the return distance is in kilometers. */ OpenLayers.Util.distVincenty = function(p1, p2) { var ct = OpenLayers.Util.VincentyConstants; var a = ct.a, b = ct.b, f = ct.f; var L = OpenLayers.Util.rad(p2.lon - p1.lon); var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat))); var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat))); var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1); var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2); var lambda = L, lambdaP = 2*Math.PI; var iterLimit = 20; while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) { var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda); var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); if (sinSigma==0) { return 0; // co-incident points } var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; var sigma = Math.atan2(sinSigma, cosSigma); var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma); var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha); var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha; var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); lambdaP = lambda; lambda = L + (1-C) * f * Math.sin(alpha) * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); } if (iterLimit==0) { return NaN; // formula failed to converge } var uSq = cosSqAlpha * (a*a - b*b) / (b*b); var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); var s = b*A*(sigma-deltaSigma); var d = s.toFixed(3)/1000; // round to 1mm precision return d; }; /** * APIFunction: destinationVincenty * Calculate destination point given start point lat/long (numeric degrees), * bearing (numeric degrees) & distance (in m). * Adapted from Chris Veness work, see * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html * * Parameters: * lonlat - {} (or any object with both .lat, .lon * properties) The start point. * brng - {Float} The bearing (degrees). * dist - {Float} The ground distance (meters). * * Returns: * {} The destination point. */ OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) { var u = OpenLayers.Util; var ct = u.VincentyConstants; var a = ct.a, b = ct.b, f = ct.f; var lon1 = lonlat.lon; var lat1 = lonlat.lat; var s = dist; var alpha1 = u.rad(brng); var sinAlpha1 = Math.sin(alpha1); var cosAlpha1 = Math.cos(alpha1); var tanU1 = (1-f) * Math.tan(u.rad(lat1)); var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1; var sigma1 = Math.atan2(tanU1, cosAlpha1); var sinAlpha = cosU1 * sinAlpha1; var cosSqAlpha = 1 - sinAlpha*sinAlpha; var uSq = cosSqAlpha * (a*a - b*b) / (b*b); var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))); var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))); var sigma = s / (b*A), sigmaP = 2*Math.PI; while (Math.abs(sigma-sigmaP) > 1e-12) { var cos2SigmaM = Math.cos(2*sigma1 + sigma); var sinSigma = Math.sin(sigma); var cosSigma = Math.cos(sigma); var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))); sigmaP = sigma; sigma = s / (b*A) + deltaSigma; } var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1; var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1, (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp)); var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1); var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)); var L = lambda - (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))); var revAz = Math.atan2(sinAlpha, -tmp); // final bearing return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2)); }; /** * Function: getParameters * Parse the parameters from a URL or from the current page itself into a * JavaScript Object. Note that parameter values with commas are separated * out into an Array. * * Parameters: * url - {String} Optional url used to extract the query string. * If url is null or is not supplied, query string is taken * from the page location. * options - {Object} Additional options. Optional. * * Valid options: * splitArgs - {Boolean} Split comma delimited params into arrays? Default is * true. * * Returns: * {Object} An object of key/value pairs from the query string. */ OpenLayers.Util.getParameters = function(url, options) { options = options || {}; // if no url specified, take it from the location bar url = (url === null || url === undefined) ? window.location.href : url; //parse out parameters portion of url string var paramsString = ""; if (OpenLayers.String.contains(url, '?')) { var start = url.indexOf('?') + 1; var end = OpenLayers.String.contains(url, "#") ? url.indexOf('#') : url.length; paramsString = url.substring(start, end); } var parameters = {}; var pairs = paramsString.split(/[&;]/); for(var i=0, len=pairs.length; i 1.0) ? (1.0 / scale) : scale; return normScale; }; /** * Function: getResolutionFromScale * * Parameters: * scale - {Float} * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. * Default is degrees * * Returns: * {Float} The corresponding resolution given passed-in scale and unit * parameters. If the given scale is falsey, the returned resolution will * be undefined. */ OpenLayers.Util.getResolutionFromScale = function (scale, units) { var resolution; if (scale) { if (units == null) { units = "degrees"; } var normScale = OpenLayers.Util.normalizeScale(scale); resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH); } return resolution; }; /** * Function: getScaleFromResolution * * Parameters: * resolution - {Float} * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable. * Default is degrees * * Returns: * {Float} The corresponding scale given passed-in resolution and unit * parameters. */ OpenLayers.Util.getScaleFromResolution = function (resolution, units) { if (units == null) { units = "degrees"; } var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] * OpenLayers.DOTS_PER_INCH; return scale; }; /** * Function: pagePosition * 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, Left value then Top value. */ 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 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; } // 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 = window.pageYOffset || viewportElement.scrollTop; var scrollLeft = window.pageXOffset || 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; } } 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; } } 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) * * Returns: * {DOMElement} */ 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 * Test two URLs for equivalence. * * Setting 'ignoreCase' allows for case-independent comparison. * * Comparison is based on: * - Protocol * - Host (evaluated without the port) * - Port (set 'ignorePort80' to ignore "80" values) * - Hash ( set 'ignoreHash' to disable) * - Pathname (for relative <-> absolute comparison) * - Arguments (so they can be out of order) * * Parameters: * url1 - {String} * url2 - {String} * options - {Object} Allows for customization of comparison: * 'ignoreCase' - Default is True * 'ignorePort80' - Default is True * 'ignoreHash' - Default is True * * Returns: * {Boolean} Whether or not the two URLs are equivalent */ OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) { options = options || {}; OpenLayers.Util.applyDefaults(options, { ignoreCase: true, ignorePort80: true, ignoreHash: true, splitArgs: false }); var urlObj1 = OpenLayers.Util.createUrlObject(url1, options); var urlObj2 = OpenLayers.Util.createUrlObject(url2, options); //compare all keys except for "args" (treated below) for(var key in urlObj1) { if(key !== "args") { if(urlObj1[key] != urlObj2[key]) { return false; } } } // compare search args - irrespective of order for(var key in urlObj1.args) { if(urlObj1.args[key] != urlObj2.args[key]) { return false; } delete urlObj2.args[key]; } // urlObj2 shouldn't have any args left for(var key in urlObj2.args) { return false; } return true; }; /** * Function: createUrlObject * * Parameters: * url - {String} * options - {Object} A hash of options. * * Valid options: * ignoreCase - {Boolean} lowercase url, * ignorePort80 - {Boolean} don't include explicit port if port is 80, * ignoreHash - {Boolean} Don't include part of url after the hash (#). * splitArgs - {Boolean} Split comma delimited params into arrays? Default is * true. * * Returns: * {Object} An object with separate url, a, port, host, and args parsed out * and ready for comparison */ OpenLayers.Util.createUrlObject = function(url, options) { options = options || {}; // deal with relative urls first if(!(/^\w+:\/\//).test(url)) { var loc = window.location; var port = loc.port ? ":" + loc.port : ""; var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port; if(url.indexOf("/") === 0) { // full pathname url = fullUrl + url; } else { // relative to current path var parts = loc.pathname.split("/"); parts.pop(); url = fullUrl + parts.join("/") + "/" + url; } } if (options.ignoreCase) { url = url.toLowerCase(); } var a = document.createElement('a'); a.href = url; var urlObject = {}; //host (without port) urlObject.host = a.host.split(":").shift(); //protocol urlObject.protocol = a.protocol; //port (get uniform browser behavior with port 80 here) if(options.ignorePort80) { urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port; } else { urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port; } //hash urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash; //args var queryString = a.search; if (!queryString) { var qMark = url.indexOf("?"); queryString = (qMark != -1) ? url.substr(qMark) : ""; } urlObject.args = OpenLayers.Util.getParameters(queryString, {splitArgs: options.splitArgs}); // pathname // // This is a workaround for Internet Explorer where // window.location.pathname has a leading "/", but // a.pathname has no leading "/". urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname; return urlObject; }; /** * Function: removeTail * Takes a url and removes everything after the ? and # * * Parameters: * url - {String} The url to process * * Returns: * {String} The string with all queryString and Hash removed */ OpenLayers.Util.removeTail = function(url) { var head = null; var qMark = url.indexOf("?"); var hashMark = url.indexOf("#"); if (qMark == -1) { head = (hashMark != -1) ? url.substr(0,hashMark) : url; } else { head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark)) : url.substr(0, qMark); } return head; }; /** * Constant: IS_GECKO * {Boolean} True if the userAgent reports the browser to use the Gecko engine */ OpenLayers.IS_GECKO = (function() { var ua = navigator.userAgent.toLowerCase(); return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1; })(); /** * Constant: CANVAS_SUPPORTED * {Boolean} True if canvas 2d is supported. */ OpenLayers.CANVAS_SUPPORTED = (function() { var elem = document.createElement('canvas'); return !!(elem.getContext && elem.getContext('2d')); })(); /** * Constant: BROWSER_NAME * {String} * A substring of the navigator.userAgent property. Depending on the userAgent * property, this will be the empty string or one of the following: * * "opera" -- Opera * * "msie" -- Internet Explorer * * "safari" -- Safari * * "firefox" -- Firefox * * "mozilla" -- Mozilla */ OpenLayers.BROWSER_NAME = (function() { var name = ""; var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf("opera") != -1) { name = "opera"; } else if (ua.indexOf("msie") != -1) { name = "msie"; } else if (ua.indexOf("safari") != -1) { name = "safari"; } else if (ua.indexOf("mozilla") != -1) { if (ua.indexOf("firefox") != -1) { name = "firefox"; } else { name = "mozilla"; } } return name; })(); /** * Function: getBrowserName * * Returns: * {String} A string which specifies which is the current * browser in which we are running. * * Currently-supported browser detection and codes: * * 'opera' -- Opera * * 'msie' -- Internet Explorer * * 'safari' -- Safari * * 'firefox' -- Firefox * * 'mozilla' -- Mozilla * * If we are unable to property identify the browser, we * return an empty string. */ OpenLayers.Util.getBrowserName = function() { return OpenLayers.BROWSER_NAME; }; /** * Method: getRenderedDimensions * Renders the contentHTML offscreen to determine actual dimensions for * popup sizing. As we need layout to determine dimensions the content * is rendered -9999px to the left and absolute to ensure the * scrollbars do not flicker * * Parameters: * contentHTML * size - {} If either the 'w' or 'h' properties is * specified, we fix that dimension of the div to be measured. This is * useful in the case where we have a limit in one dimension and must * therefore meaure the flow in the other dimension. * options - {Object} * * Allowed Options: * displayClass - {String} Optional parameter. A CSS class name(s) string * to provide the CSS context of the rendered content. * containerElement - {DOMElement} Optional parameter. Insert the HTML to * this node instead of the body root when calculating dimensions. * * Returns: * {} */ OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) { var w, h; // create temp container div with restricted size var container = document.createElement("div"); container.style.visibility = "hidden"; var containerElement = (options && options.containerElement) ? options.containerElement : document.body; // Opera and IE7 can't handle a node with position:aboslute if it inherits // position:absolute from a parent. var parentHasPositionAbsolute = false; var superContainer = null; var parent = containerElement; while (parent && parent.tagName.toLowerCase()!="body") { var parentPosition = OpenLayers.Element.getStyle(parent, "position"); if(parentPosition == "absolute") { parentHasPositionAbsolute = true; break; } else if (parentPosition && parentPosition != "static") { break; } parent = parent.parentNode; } if(parentHasPositionAbsolute && (containerElement.clientHeight === 0 || containerElement.clientWidth === 0) ){ superContainer = document.createElement("div"); superContainer.style.visibility = "hidden"; superContainer.style.position = "absolute"; superContainer.style.overflow = "visible"; superContainer.style.width = document.body.clientWidth + "px"; superContainer.style.height = document.body.clientHeight + "px"; superContainer.appendChild(container); } container.style.position = "absolute"; //fix a dimension, if specified. if (size) { if (size.w) { w = size.w; container.style.width = w + "px"; } else if (size.h) { h = size.h; container.style.height = h + "px"; } } //add css classes, if specified if (options && options.displayClass) { container.className = options.displayClass; } // create temp content div and assign content var content = document.createElement("div"); content.innerHTML = contentHTML; // we need overflow visible when calculating the size content.style.overflow = "visible"; if (content.childNodes) { for (var i=0, l=content.childNodes.length; i= 60) { coordinateseconds -= 60; coordinateminutes += 1; if( coordinateminutes >= 60) { coordinateminutes -= 60; coordinatedegrees += 1; } } if( coordinatedegrees < 10 ) { coordinatedegrees = "0" + coordinatedegrees; } var str = coordinatedegrees + "\u00B0"; if (dmsOption.indexOf('dm') >= 0) { if( coordinateminutes < 10 ) { coordinateminutes = "0" + coordinateminutes; } str += coordinateminutes + "'"; if (dmsOption.indexOf('dms') >= 0) { if( coordinateseconds < 10 ) { coordinateseconds = "0" + coordinateseconds; } str += coordinateseconds + '"'; } } if (axis == "lon") { str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E"); } else { str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); } return str; };