/ajax/libs/openlayers/2.12/OpenLayers.debug.js
JavaScript | 14899 lines | 11931 code | 433 blank | 2535 comment | 547 complexity | 19ceef888620f331b6e2c80d6617606a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
- /*
- OpenLayers.js -- OpenLayers Map Viewer Library
- Copyright (c) 2006-2012 by OpenLayers Contributors
- Published under the 2-clause BSD license.
- See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
- Includes compressed code under the following licenses:
- (For uncompressed versions of the code used, please see the
- OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
- */
- /**
- * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
- * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- */
- /**
- * 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.
- */
- /* ======================================================================
- OpenLayers/SingleFile.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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. */
- var OpenLayers = {
- /**
- * Constant: VERSION_NUMBER
- */
- VERSION_NUMBER: "Release 2.12",
- /**
- * Constant: singleFile
- * TODO: remove this in 3.0 when we stop supporting build profiles that
- * include OpenLayers.js
- */
- singleFile: true,
- /**
- * Method: _getScriptLocation
- * Return the path to this script. This is also implemented in
- * OpenLayers.js
- *
- * Returns:
- * {String} Path to this script
- */
- _getScriptLocation: (function() {
- var r = new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),
- s = document.getElementsByTagName('script'),
- src, m, l = "";
- for(var i=0, len=s.length; i<len; i++) {
- src = s[i].getAttribute('src');
- if(src) {
- m = src.match(r);
- if(m) {
- l = m[1];
- break;
- }
- }
- }
- return (function() { return l; });
- })(),
-
- /**
- * Property: ImgPath
- * {String} Set this to the path where control images are stored, a path
- * given here must end with a slash. If set to '' (which is the default)
- * OpenLayers will use its script location + "img/".
- *
- * You will need to set this property when you have a singlefile build of
- * OpenLayers that either is not named "OpenLayers.js" or if you move
- * the file in a way such that the image directory cannot be derived from
- * the script location.
- *
- * If your custom OpenLayers build is named "my-custom-ol.js" and the images
- * of OpenLayers are in a folder "/resources/external/images/ol" a correct
- * way of including OpenLayers in your HTML would be:
- *
- * (code)
- * <script src="/path/to/my-custom-ol.js" type="text/javascript"></script>
- * <script type="text/javascript">
- * // tell OpenLayers where the control images are
- * // remember the trailing slash
- * OpenLayers.ImgPath = "/resources/external/images/ol/";
- * </script>
- * (end code)
- *
- * Please remember that when your OpenLayers script is not named
- * "OpenLayers.js" you will have to make sure that the default theme is
- * loaded into the page by including an appropriate <link>-tag,
- * e.g.:
- *
- * (code)
- * <link rel="stylesheet" href="/path/to/default/style.css" type="text/css">
- * (end code)
- */
- ImgPath : ''
- };
- /* ======================================================================
- OpenLayers/BaseTypes/Class.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/SingleFile.js
- */
- /**
- * Constructor: OpenLayers.Class
- * Base class used to construct all other classes. Includes support for
- * multiple inheritance.
- *
- * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old
- * syntax for creating classes and dealing with inheritance
- * will be removed.
- *
- * To create a new OpenLayers-style class, use the following syntax:
- * (code)
- * var MyClass = OpenLayers.Class(prototype);
- * (end)
- *
- * To create a new OpenLayers-style class with multiple inheritance, use the
- * following syntax:
- * (code)
- * var MyClass = OpenLayers.Class(Class1, Class2, prototype);
- * (end)
- *
- * Note that instanceof reflection will only reveal Class1 as superclass.
- *
- */
- OpenLayers.Class = function() {
- var len = arguments.length;
- var P = arguments[0];
- var F = arguments[len-1];
- var C = typeof F.initialize == "function" ?
- F.initialize :
- function(){ P.prototype.initialize.apply(this, arguments); };
- if (len > 1) {
- var newArgs = [C, P].concat(
- Array.prototype.slice.call(arguments).slice(1, len-1), F);
- OpenLayers.inherit.apply(null, newArgs);
- } else {
- C.prototype = F;
- }
- return C;
- };
- /**
- * Function: OpenLayers.inherit
- *
- * Parameters:
- * C - {Object} the class that inherits
- * P - {Object} the superclass to inherit from
- *
- * In addition to the mandatory C and P parameters, an arbitrary number of
- * objects can be passed, which will extend C.
- */
- OpenLayers.inherit = function(C, P) {
- var F = function() {};
- F.prototype = P.prototype;
- C.prototype = new F;
- var i, l, o;
- for(i=2, l=arguments.length; i<l; i++) {
- o = arguments[i];
- if(typeof o === "function") {
- o = o.prototype;
- }
- OpenLayers.Util.extend(C.prototype, o);
- }
- };
- /**
- * APIFunction: extend
- * Copy all properties of a source object to a destination object. Modifies
- * the passed in destination object. Any properties on the source object
- * that are set to undefined will not be (re)set on the destination object.
- *
- * Parameters:
- * destination - {Object} The object that will be modified
- * source - {Object} The object with properties to be set on the destination
- *
- * Returns:
- * {Object} The destination object.
- */
- OpenLayers.Util = OpenLayers.Util || {};
- OpenLayers.Util.extend = function(destination, source) {
- destination = destination || {};
- if (source) {
- for (var property in source) {
- var value = source[property];
- if (value !== undefined) {
- destination[property] = value;
- }
- }
- /**
- * 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.
- */
- /*
- * 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 sourceIsEvt = typeof window.Event == "function"
- && source instanceof window.Event;
- if (!sourceIsEvt
- && source.hasOwnProperty && source.hasOwnProperty("toString")) {
- destination.toString = source.toString;
- }
- }
- return destination;
- };
- /* ======================================================================
- OpenLayers/BaseTypes.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/SingleFile.js
- */
- /**
- * Header: OpenLayers Base Types
- * OpenLayers custom string, number and function functions are described here.
- */
- /**
- * Namespace: OpenLayers.String
- * Contains convenience functions for string manipulation.
- */
- OpenLayers.String = {
- /**
- * APIFunction: startsWith
- * Test whether a string starts with another string.
- *
- * Parameters:
- * str - {String} The string to test.
- * sub - {String} The substring to look for.
- *
- * Returns:
- * {Boolean} The first string starts with the second.
- */
- startsWith: function(str, sub) {
- return (str.indexOf(sub) == 0);
- },
- /**
- * APIFunction: contains
- * Test whether a string contains another string.
- *
- * Parameters:
- * str - {String} The string to test.
- * sub - {String} The substring to look for.
- *
- * Returns:
- * {Boolean} The first string contains the second.
- */
- contains: function(str, sub) {
- return (str.indexOf(sub) != -1);
- },
-
- /**
- * APIFunction: trim
- * Removes leading and trailing whitespace characters from a string.
- *
- * Parameters:
- * str - {String} The (potentially) space padded string. This string is not
- * modified.
- *
- * Returns:
- * {String} A trimmed version of the string with all leading and
- * trailing spaces removed.
- */
- trim: function(str) {
- return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- },
-
- /**
- * APIFunction: camelize
- * Camel-case a hyphenated string.
- * Ex. "chicken-head" becomes "chickenHead", and
- * "-chicken-head" becomes "ChickenHead".
- *
- * Parameters:
- * str - {String} The string to be camelized. The original is not modified.
- *
- * Returns:
- * {String} The string, camelized
- */
- camelize: function(str) {
- var oStringList = str.split('-');
- var camelizedString = oStringList[0];
- for (var i=1, len=oStringList.length; i<len; i++) {
- var s = oStringList[i];
- camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
- }
- return camelizedString;
- },
-
- /**
- * APIFunction: format
- * Given a string with tokens in the form ${token}, return a string
- * with tokens replaced with properties from the given context
- * object. Represent a literal "${" by doubling it, e.g. "${${".
- *
- * Parameters:
- * template - {String} A string with tokens to be replaced. A template
- * has the form "literal ${token}" where the token will be replaced
- * by the value of context["token"].
- * context - {Object} An optional object with properties corresponding
- * to the tokens in the format string. If no context is sent, the
- * window object will be used.
- * args - {Array} Optional arguments to pass to any functions found in
- * the context. If a context property is a function, the token
- * will be replaced by the return from the function called with
- * these arguments.
- *
- * Returns:
- * {String} A string with tokens replaced from the context object.
- */
- format: function(template, context, args) {
- if(!context) {
- context = window;
- }
- // Example matching:
- // str = ${foo.bar}
- // match = foo.bar
- var replacer = function(str, match) {
- var replacement;
- // Loop through all subs. Example: ${a.b.c}
- // 0 -> replacement = context[a];
- // 1 -> replacement = context[a][b];
- // 2 -> replacement = context[a][b][c];
- var subs = match.split(/\.+/);
- for (var i=0; i< subs.length; i++) {
- if (i == 0) {
- replacement = context;
- }
- replacement = replacement[subs[i]];
- }
- if(typeof replacement == "function") {
- replacement = args ?
- replacement.apply(null, args) :
- replacement();
- }
- // If replacement is undefined, return the string 'undefined'.
- // This is a workaround for a bugs in browsers not properly
- // dealing with non-participating groups in regular expressions:
- // http://blog.stevenlevithan.com/archives/npcg-javascript
- if (typeof replacement == 'undefined') {
- return 'undefined';
- } else {
- return replacement;
- }
- };
- return template.replace(OpenLayers.String.tokenRegEx, replacer);
- },
- /**
- * Property: tokenRegEx
- * Used to find tokens in a string.
- * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
- */
- tokenRegEx: /\$\{([\w.]+?)\}/g,
-
- /**
- * Property: numberRegEx
- * Used to test strings as numbers.
- */
- numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
-
- /**
- * APIFunction: isNumeric
- * Determine whether a string contains only a numeric value.
- *
- * Examples:
- * (code)
- * OpenLayers.String.isNumeric("6.02e23") // true
- * OpenLayers.String.isNumeric("12 dozen") // false
- * OpenLayers.String.isNumeric("4") // true
- * OpenLayers.String.isNumeric(" 4 ") // false
- * (end)
- *
- * Returns:
- * {Boolean} String contains only a number.
- */
- isNumeric: function(value) {
- return OpenLayers.String.numberRegEx.test(value);
- },
-
- /**
- * APIFunction: numericIf
- * Converts a string that appears to be a numeric value into a number.
- *
- * Parameters:
- * value - {String}
- *
- * Returns:
- * {Number|String} a Number if the passed value is a number, a String
- * otherwise.
- */
- numericIf: function(value) {
- return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value;
- }
- };
- /**
- * Namespace: OpenLayers.Number
- * Contains convenience functions for manipulating numbers.
- */
- OpenLayers.Number = {
- /**
- * Property: decimalSeparator
- * Decimal separator to use when formatting numbers.
- */
- decimalSeparator: ".",
-
- /**
- * Property: thousandsSeparator
- * Thousands separator to use when formatting numbers.
- */
- thousandsSeparator: ",",
-
- /**
- * APIFunction: limitSigDigs
- * Limit the number of significant digits on a float.
- *
- * Parameters:
- * num - {Float}
- * sig - {Integer}
- *
- * Returns:
- * {Float} The number, rounded to the specified number of significant
- * digits.
- */
- limitSigDigs: function(num, sig) {
- var fig = 0;
- if (sig > 0) {
- fig = parseFloat(num.toPrecision(sig));
- }
- return fig;
- },
-
- /**
- * APIFunction: format
- * Formats a number for output.
- *
- * Parameters:
- * num - {Float}
- * dec - {Integer} Number of decimal places to round to.
- * Defaults to 0. Set to null to leave decimal places unchanged.
- * tsep - {String} Thousands separator.
- * Default is ",".
- * dsep - {String} Decimal separator.
- * Default is ".".
- *
- * Returns:
- * {String} A string representing the formatted number.
- */
- format: function(num, dec, tsep, dsep) {
- dec = (typeof dec != "undefined") ? dec : 0;
- tsep = (typeof tsep != "undefined") ? tsep :
- OpenLayers.Number.thousandsSeparator;
- dsep = (typeof dsep != "undefined") ? dsep :
- OpenLayers.Number.decimalSeparator;
- if (dec != null) {
- num = parseFloat(num.toFixed(dec));
- }
- var parts = num.toString().split(".");
- if (parts.length == 1 && dec == null) {
- // integer where we do not want to touch the decimals
- dec = 0;
- }
-
- var integer = parts[0];
- if (tsep) {
- var thousands = /(-?[0-9]+)([0-9]{3})/;
- while(thousands.test(integer)) {
- integer = integer.replace(thousands, "$1" + tsep + "$2");
- }
- }
-
- var str;
- if (dec == 0) {
- str = integer;
- } else {
- var rem = parts.length > 1 ? parts[1] : "0";
- if (dec != null) {
- rem = rem + new Array(dec - rem.length + 1).join("0");
- }
- str = integer + dsep + rem;
- }
- return str;
- }
- };
- /**
- * Namespace: OpenLayers.Function
- * Contains convenience functions for function manipulation.
- */
- OpenLayers.Function = {
- /**
- * APIFunction: bind
- * Bind a function to an object. Method to easily create closures with
- * 'this' altered.
- *
- * Parameters:
- * func - {Function} Input function.
- * object - {Object} The object to bind to the input function (as this).
- *
- * Returns:
- * {Function} A closure with 'this' set to the passed in object.
- */
- bind: function(func, object) {
- // create a reference to all arguments past the second one
- var args = Array.prototype.slice.apply(arguments, [2]);
- return function() {
- // Push on any additional arguments from the actual function call.
- // These will come after those sent to the bind call.
- var newArgs = args.concat(
- Array.prototype.slice.apply(arguments, [0])
- );
- return func.apply(object, newArgs);
- };
- },
-
- /**
- * APIFunction: bindAsEventListener
- * Bind a function to an object, and configure it to receive the event
- * object as first parameter when called.
- *
- * Parameters:
- * func - {Function} Input function to serve as an event listener.
- * object - {Object} A reference to this.
- *
- * Returns:
- * {Function}
- */
- bindAsEventListener: function(func, object) {
- return function(event) {
- return func.call(object, event || window.event);
- };
- },
-
- /**
- * APIFunction: False
- * A simple function to that just does "return false". We use this to
- * avoid attaching anonymous functions to DOM event handlers, which
- * causes "issues" on IE<8.
- *
- * Usage:
- * document.onclick = OpenLayers.Function.False;
- *
- * Returns:
- * {Boolean}
- */
- False : function() {
- return false;
- },
- /**
- * APIFunction: True
- * A simple function to that just does "return true". We use this to
- * avoid attaching anonymous functions to DOM event handlers, which
- * causes "issues" on IE<8.
- *
- * Usage:
- * document.onclick = OpenLayers.Function.True;
- *
- * Returns:
- * {Boolean}
- */
- True : function() {
- return true;
- },
-
- /**
- * APIFunction: Void
- * A reusable function that returns ``undefined``.
- *
- * Returns:
- * {undefined}
- */
- Void: function() {}
- };
- /**
- * Namespace: OpenLayers.Array
- * Contains convenience functions for array manipulation.
- */
- OpenLayers.Array = {
- /**
- * APIMethod: filter
- * Filter an array. Provides the functionality of the
- * Array.prototype.filter extension to the ECMA-262 standard. Where
- * available, Array.prototype.filter will be used.
- *
- * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter
- *
- * Parameters:
- * array - {Array} The array to be filtered. This array is not mutated.
- * Elements added to this array by the callback will not be visited.
- * callback - {Function} A function that is called for each element in
- * the array. If this function returns true, the element will be
- * included in the return. The function will be called with three
- * arguments: the element in the array, the index of that element, and
- * the array itself. If the optional caller parameter is specified
- * the callback will be called with this set to caller.
- * caller - {Object} Optional object to be set as this when the callback
- * is called.
- *
- * Returns:
- * {Array} An array of elements from the passed in array for which the
- * callback returns true.
- */
- filter: function(array, callback, caller) {
- var selected = [];
- if (Array.prototype.filter) {
- selected = array.filter(callback, caller);
- } else {
- var len = array.length;
- if (typeof callback != "function") {
- throw new TypeError();
- }
- for(var i=0; i<len; i++) {
- if (i in array) {
- var val = array[i];
- if (callback.call(caller, val, i, array)) {
- selected.push(val);
- }
- }
- }
- }
- return selected;
- }
-
- };
- /* ======================================================================
- OpenLayers/BaseTypes/Bounds.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Class: OpenLayers.Bounds
- * Instances of this class represent bounding boxes. Data stored as left,
- * bottom, right, top floats. All values are initialized to null, however,
- * you should make sure you set them before using the bounds for anything.
- *
- * Possible use case:
- * (code)
- * bounds = new OpenLayers.Bounds();
- * bounds.extend(new OpenLayers.LonLat(4,5));
- * bounds.extend(new OpenLayers.LonLat(5,6));
- * bounds.toBBOX(); // returns 4,5,5,6
- * (end)
- */
- OpenLayers.Bounds = OpenLayers.Class({
- /**
- * Property: left
- * {Number} Minimum horizontal coordinate.
- */
- left: null,
- /**
- * Property: bottom
- * {Number} Minimum vertical coordinate.
- */
- bottom: null,
- /**
- * Property: right
- * {Number} Maximum horizontal coordinate.
- */
- right: null,
- /**
- * Property: top
- * {Number} Maximum vertical coordinate.
- */
- top: null,
-
- /**
- * Property: centerLonLat
- * {<OpenLayers.LonLat>} A cached center location. This should not be
- * accessed directly. Use <getCenterLonLat> instead.
- */
- centerLonLat: null,
- /**
- * Constructor: OpenLayers.Bounds
- * Construct a new bounds object. Coordinates can either be passed as four
- * arguments, or as a single argument.
- *
- * Parameters (four arguments):
- * left - {Number} The left bounds of the box. Note that for width
- * calculations, this is assumed to be less than the right value.
- * bottom - {Number} The bottom bounds of the box. Note that for height
- * calculations, this is assumed to be more than the top value.
- * right - {Number} The right bounds.
- * top - {Number} The top bounds.
- *
- * Parameters (single argument):
- * bounds - {Array(Number)} [left, bottom, right, top]
- */
- initialize: function(left, bottom, right, top) {
- if (OpenLayers.Util.isArray(left)) {
- top = left[3];
- right = left[2];
- bottom = left[1];
- left = left[0];
- }
- if (left != null) {
- this.left = OpenLayers.Util.toFloat(left);
- }
- if (bottom != null) {
- this.bottom = OpenLayers.Util.toFloat(bottom);
- }
- if (right != null) {
- this.right = OpenLayers.Util.toFloat(right);
- }
- if (top != null) {
- this.top = OpenLayers.Util.toFloat(top);
- }
- },
- /**
- * Method: clone
- * Create a cloned instance of this bounds.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A fresh copy of the bounds
- */
- clone:function() {
- return new OpenLayers.Bounds(this.left, this.bottom,
- this.right, this.top);
- },
- /**
- * Method: equals
- * Test a two bounds for equivalence.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {Boolean} The passed-in bounds object has the same left,
- * right, top, bottom components as this. Note that if bounds
- * passed in is null, returns false.
- */
- equals:function(bounds) {
- var equals = false;
- if (bounds != null) {
- equals = ((this.left == bounds.left) &&
- (this.right == bounds.right) &&
- (this.top == bounds.top) &&
- (this.bottom == bounds.bottom));
- }
- return equals;
- },
- /**
- * APIMethod: toString
- *
- * Returns:
- * {String} String representation of bounds object.
- */
- toString:function() {
- return [this.left, this.bottom, this.right, this.top].join(",");
- },
- /**
- * APIMethod: toArray
- *
- * Parameters:
- * reverseAxisOrder - {Boolean} Should we reverse the axis order?
- *
- * Returns:
- * {Array} array of left, bottom, right, top
- */
- toArray: function(reverseAxisOrder) {
- if (reverseAxisOrder === true) {
- return [this.bottom, this.left, this.top, this.right];
- } else {
- return [this.left, this.bottom, this.right, this.top];
- }
- },
- /**
- * APIMethod: toBBOX
- *
- * Parameters:
- * decimal - {Integer} How many significant digits in the bbox coords?
- * Default is 6
- * reverseAxisOrder - {Boolean} Should we reverse the axis order?
- *
- * Returns:
- * {String} Simple String representation of bounds object.
- * (e.g. <i>"5,42,10,45"</i>)
- */
- toBBOX:function(decimal, reverseAxisOrder) {
- if (decimal== null) {
- decimal = 6;
- }
- var mult = Math.pow(10, decimal);
- var xmin = Math.round(this.left * mult) / mult;
- var ymin = Math.round(this.bottom * mult) / mult;
- var xmax = Math.round(this.right * mult) / mult;
- var ymax = Math.round(this.top * mult) / mult;
- if (reverseAxisOrder === true) {
- return ymin + "," + xmin + "," + ymax + "," + xmax;
- } else {
- return xmin + "," + ymin + "," + xmax + "," + ymax;
- }
- },
-
- /**
- * APIMethod: toGeometry
- * Create a new polygon geometry based on this bounds.
- *
- * Returns:
- * {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
- * of this bounds.
- */
- toGeometry: function() {
- return new OpenLayers.Geometry.Polygon([
- new OpenLayers.Geometry.LinearRing([
- new OpenLayers.Geometry.Point(this.left, this.bottom),
- new OpenLayers.Geometry.Point(this.right, this.bottom),
- new OpenLayers.Geometry.Point(this.right, this.top),
- new OpenLayers.Geometry.Point(this.left, this.top)
- ])
- ]);
- },
-
- /**
- * APIMethod: getWidth
- *
- * Returns:
- * {Float} The width of the bounds
- */
- getWidth:function() {
- return (this.right - this.left);
- },
- /**
- * APIMethod: getHeight
- *
- * Returns:
- * {Float} The height of the bounds (top minus bottom).
- */
- getHeight:function() {
- return (this.top - this.bottom);
- },
- /**
- * APIMethod: getSize
- *
- * Returns:
- * {<OpenLayers.Size>} The size of the box.
- */
- getSize:function() {
- return new OpenLayers.Size(this.getWidth(), this.getHeight());
- },
- /**
- * APIMethod: getCenterPixel
- *
- * Returns:
- * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
- */
- getCenterPixel:function() {
- return new OpenLayers.Pixel( (this.left + this.right) / 2,
- (this.bottom + this.top) / 2);
- },
- /**
- * APIMethod: getCenterLonLat
- *
- * Returns:
- * {<OpenLayers.LonLat>} The center of the bounds in map space.
- */
- getCenterLonLat:function() {
- if(!this.centerLonLat) {
- this.centerLonLat = new OpenLayers.LonLat(
- (this.left + this.right) / 2, (this.bottom + this.top) / 2
- );
- }
- return this.centerLonLat;
- },
- /**
- * APIMethod: scale
- * Scales the bounds around a pixel or lonlat. Note that the new
- * bounds may return non-integer properties, even if a pixel
- * is passed.
- *
- * Parameters:
- * ratio - {Float}
- * origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
- * Default is center.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A new bounds that is scaled by ratio
- * from origin.
- */
- scale: function(ratio, origin){
- if(origin == null){
- origin = this.getCenterLonLat();
- }
-
- var origx,origy;
- // get origin coordinates
- if(origin.CLASS_NAME == "OpenLayers.LonLat"){
- origx = origin.lon;
- origy = origin.lat;
- } else {
- origx = origin.x;
- origy = origin.y;
- }
- var left = (this.left - origx) * ratio + origx;
- var bottom = (this.bottom - origy) * ratio + origy;
- var right = (this.right - origx) * ratio + origx;
- var top = (this.top - origy) * ratio + origy;
-
- return new OpenLayers.Bounds(left, bottom, right, top);
- },
- /**
- * APIMethod: add
- *
- * Parameters:
- * x - {Float}
- * y - {Float}
- *
- * Returns:
- * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
- * this, but shifted by the passed-in x and y values.
- */
- add:function(x, y) {
- if ( (x == null) || (y == null) ) {
- throw new TypeError('Bounds.add cannot receive null values');
- }
- return new OpenLayers.Bounds(this.left + x, this.bottom + y,
- this.right + x, this.top + y);
- },
-
- /**
- * APIMethod: extend
- * Extend the bounds to include the point, lonlat, or bounds specified.
- * Note, this function assumes that left < right and bottom < top.
- *
- * Parameters:
- * object - {Object} Can be LonLat, Point, or Bounds
- */
- extend:function(object) {
- var bounds = null;
- if (object) {
- // clear cached center location
- switch(object.CLASS_NAME) {
- case "OpenLayers.LonLat":
- bounds = new OpenLayers.Bounds(object.lon, object.lat,
- object.lon, object.lat);
- break;
- case "OpenLayers.Geometry.Point":
- bounds = new OpenLayers.Bounds(object.x, object.y,
- object.x, object.y);
- break;
-
- case "OpenLayers.Bounds":
- bounds = object;
- break;
- }
-
- if (bounds) {
- this.centerLonLat = null;
- if ( (this.left == null) || (bounds.left < this.left)) {
- this.left = bounds.left;
- }
- if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
- this.bottom = bounds.bottom;
- }
- if ( (this.right == null) || (bounds.right > this.right) ) {
- this.right = bounds.right;
- }
- if ( (this.top == null) || (bounds.top > this.top) ) {
- this.top = bounds.top;
- }
- }
- }
- },
- /**
- * APIMethod: containsLonLat
- *
- * Parameters:
- * ll - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
- * object with a 'lon' and 'lat' properties.
- * options - {Object} Optional parameters
- *
- * Acceptable options:
- * inclusive - {Boolean} Whether or not to include the border.
- * Default is true.
- * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, the
- * ll will be considered as contained if it exceeds the world bounds,
- * but can be wrapped around the dateline so it is contained by this
- * bounds.
- *
- * Returns:
- * {Boolean} The passed-in lonlat is within this bounds.
- */
- containsLonLat: function(ll, options) {
- if (typeof options === "boolean") {
- options = {inclusive: options};
- }
- options = options || {};
- var contains = this.contains(ll.lon, ll.lat, options.inclusive),
- worldBounds = options.worldBounds;
- if (worldBounds && !contains) {
- var worldWidth = worldBounds.getWidth();
- var worldCenterX = (worldBounds.left + worldBounds.right) / 2;
- var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth);
- contains = this.containsLonLat({
- lon: ll.lon - worldsAway * worldWidth,
- lat: ll.lat
- }, {inclusive: options.inclusive});
- }
- return contains;
- },
- /**
- * APIMethod: containsPixel
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- * inclusive - {Boolean} Whether or not to include the border. Default is
- * true.
- *
- * Returns:
- * {Boolean} The passed-in pixel is within this bounds.
- */
- containsPixel:function(px, inclusive) {
- return this.contains(px.x, px.y, inclusive);
- },
-
- /**
- * APIMethod: contains
- *
- * Parameters:
- * x - {Float}
- * y - {Float}
- * inclusive - {Boolean} Whether or not to include the border. Default is
- * true.
- *
- * Returns:
- * {Boolean} Whether or not the passed-in coordinates are within this
- * bounds.
- */
- contains:function(x, y, inclusive) {
- //set default
- if (inclusive == null) {
- inclusive = true;
- }
- if (x == null || y == null) {
- return false;
- }
- x = OpenLayers.Util.toFloat(x);
- y = OpenLayers.Util.toFloat(y);
- var contains = false;
- if (inclusive) {
- contains = ((x >= this.left) && (x <= this.right) &&
- (y >= this.bottom) && (y <= this.top));
- } else {
- contains = ((x > this.left) && (x < this.right) &&
- (y > this.bottom) && (y < this.top));
- }
- return contains;
- },
- /**
- * APIMethod: intersectsBounds
- * Determine whether the target bounds intersects this bounds. Bounds are
- * considered intersecting if any of their edges intersect or if one
- * bounds contains the other.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} The target bounds.
- * options - {Object} Optional parameters.
- *
- * Acceptable options:
- * inclusive - {Boolean} Treat coincident borders as intersecting. Default
- * is true. If false, bounds that do not overlap but only touch at the
- * border will not be considered as intersecting.
- * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, two
- * bounds will be considered as intersecting if they intersect when
- * shifted to within the world bounds. This applies only to bounds that
- * cross or are completely outside the world bounds.
- *
- * Returns:
- * {Boolean} The passed-in bounds object intersects this bounds.
- */
- intersectsBounds:function(bounds, options) {
- if (typeof options === "boolean") {
- options = {inclusive: options};
- }
- options = options || {};
- if (options.worldBounds) {
- var self = this.wrapDateLine(options.worldBounds);
- bounds = bounds.wrapDateLine(options.worldBounds);
- } else {
- self = this;
- }
- if (options.inclusive == null) {
- options.inclusive = true;
- }
- var intersects = false;
- var mightTouch = (
- self.left == bounds.right ||
- self.right == bounds.left ||
- self.top == bounds.bottom ||
- self.bottom == bounds.top
- );
-
- // if the two bounds only touch at an edge, and inclusive is false,
- // then the bounds don't *really* intersect.
- if (options.inclusive || !mightTouch) {
- // otherwise, if one of the boundaries even partially contains another,
- // inclusive of the edges, then they do intersect.
- var inBottom = (
- ((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) ||
- ((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top))
- );
- var inTop = (
- ((bounds.top >= self.bottom) && (bounds.top <= self.top)) ||
- ((self.top > bounds.bottom) && (self.top < bounds.top))
- );
- var inLeft = (
- ((bounds.left >= self.left) && (bounds.left <= self.right)) ||
- ((self.left >= bounds.left) && (self.left <= bounds.right))
- );
- var inRight = (
- ((bounds.right >= self.left) && (bounds.right <= self.right)) ||
- ((self.right >= bounds.left) && (self.right <= bounds.right))
- );
- intersects = ((inBottom || inTop) && (inLeft || inRight));
- }
- // document me
- if (options.worldBounds && !intersects) {
- var world = options.worldBounds;
- var width = world.getWidth();
- var selfCrosses = !world.containsBounds(self);
- var boundsCrosses = !world.containsBounds(bounds);
- if (selfCrosses && !boundsCrosses) {
- bounds = bounds.add(-width, 0);
- intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive});
- } else if (boundsCrosses && !selfCrosses) {
- self = self.add(-width, 0);
- intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive});
- }
- }
- return intersects;
- },
-
- /**
- * APIMethod: containsBounds
- * Determine whether the target bounds is contained within this bounds.
- *
- * bounds - {<OpenLayers.Bounds>} The target bounds.
- * partial - {Boolean} If any of the target corners is within this bounds
- * consider the bounds contained. Default is false. If false, the
- * entire target bounds must be contained within this bounds.
- * inclusive - {Boolean} Treat shared edges as contained. Default is
- * true.
- *
- * Returns:
- * {Boolean} The passed-in bounds object is contained within this bounds.
- */
- containsBounds:function(bounds, partial, inclusive) {
- if (partial == null) {
- partial = false;
- }
- if (inclusive == null) {
- inclusive = true;
- }
- var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive);
- var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
- var topLeft = this.contains(bounds.left, bounds.top, inclusive);
- var topRight = this.contains(bounds.right, bounds.top, inclusive);
-
- return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
- : (bottomLeft && bottomRight && topLeft && topRight);
- },
- /**
- * APIMethod: determineQuadrant
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
- * coordinate lies.
- */
- determineQuadrant: function(lonlat) {
-
- var quadrant = "";
- var center = this.getCenterLonLat();
-
- quadrant += (lonlat.lat < center.lat) ? "b" : "t";
- quadrant += (lonlat.lon < center.lon) ? "l" : "r";
-
- return quadrant;
- },
-
- /**
- * APIMethod: transform
- * Transform the Bounds object from source to dest.
- *
- * Parameters:
- * source - {<OpenLayers.Projection>} Source projection.
- * dest - {<OpenLayers.Projection>} Destination projection.
- *
- * Returns:
- * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
- */
- transform: function(source, dest) {
- // clear cached center location
- this.centerLonLat = null;
- var ll = OpenLayers.Projection.transform(
- {'x': this.left, 'y': this.bottom}, source, dest);
- var lr = OpenLayers.Projection.transform(
- {'x': this.right, 'y': this.bottom}, source, dest);
- var ul = OpenLayers.Projection.transform(
- {'x': this.left, 'y': this.top}, source, dest);
- var ur = OpenLayers.Projection.transform(
- {'x': this.right, 'y': this.top}, source, dest);
- this.left = Math.min(ll.x, ul.x);
- this.bottom = Math.min(ll.y, lr.y);
- this.right = Math.max(lr.x, ur.x);
- this.top = Math.max(ul.y, ur.y);
- return this;
- },
- /**
- * APIMethod: wrapDateLine
- *
- * Parameters:
- * maxExtent - {<OpenLayers.Bounds>}
- * options - {Object} Some possible options are:
- *
- * Allowed Options:
- * leftTolerance - {float} Allow for a margin of error
- * with the 'left' value of this
- * bound.
- * Default is 0.
- * rightTolerance - {float} Allow for a margin of error
- * with the 'right' value of
- * this bound.
- * Default is 0.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the
- * "dateline" (as specified by the borders of
- * maxExtent). Note that this function only returns
- * a different bounds value if this bounds is
- * *entirely* outside of the maxExtent. If this
- * bounds straddles the dateline (is part in/part
- * out of maxExtent), the returned bounds will always
- * cross the left edge of the given maxExtent.
- *.
- */
- wrapDateLine: function(maxExtent, options) {
- options = options || {};
-
- var leftTolerance = options.leftTolerance || 0;
- var rightTolerance = options.rightTolerance || 0;
- var newBounds = this.clone();
-
- if (maxExtent) {
- var width = maxExtent.getWidth();
- //shift right?
- while (newBounds.left < maxExtent.left &&
- newBounds.right - rightTolerance <= maxExtent.left ) {
- newBounds = newBounds.add(width, 0);
- }
- //shift left?
- while (newBounds.left + leftTolerance >= maxExtent.right &&
- newBounds.right > maxExtent.right ) {
- newBounds = newBounds.add(-width, 0);
- }
-
- // crosses right only? force left
- var newLeft = newBounds.left + leftTolerance;
- if (newLeft < maxExtent.right && newLeft > maxExtent.left &&
- newBounds.right - rightTolerance > maxExtent.right) {
- newBounds = newBounds.add(-width, 0);
- }
- }
-
- return newBounds;
- },
- CLASS_NAME: "OpenLayers.Bounds"
- });
- /**
- * APIFunction: fromString
- * Alternative constructor that builds a new OpenLayers.Bounds from a
- * parameter string
- *
- * Parameters:
- * str - {String}Comma-separated bounds string. (e.g. <i>"5,42,10,45"</i>)
- * reverseAxisOrder - {Boolean} Does the string use reverse axis order?
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the
- * passed-in String.
- */
- OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
- var bounds = str.split(",");
- return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
- };
- /**
- * APIFunction: fromArray
- * Alternative constructor that builds a new OpenLayers.Bounds
- * from an array
- *
- * Parameters:
- * bbox - {Array(Float)} Array of bounds values (e.g. <i>[5,42,10,45]</i>)
- * reverseAxisOrder - {Boolean} Does the array use reverse axis order?
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
- */
- OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
- return reverseAxisOrder === true ?
- new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) :
- new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]);
- };
- /**
- * APIFunction: fromSize
- * Alternative constructor that builds a new OpenLayers.Bounds
- * from a size
- *
- * Parameters:
- * size - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
- * a 'w' and 'h' properties.
- *
- * Returns:
- * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
- */
- OpenLayers.Bounds.fromSize = function(size) {
- return new OpenLayers.Bounds(0,
- size.h,
- size.w,
- 0);
- };
- /**
- * Function: oppositeQuadrant
- * Get the opposite quadrant for a given quadrant string.
- *
- * Parameters:
- * quadrant - {String} two character quadrant shortstring
- *
- * Returns:
- * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if
- * you pass in "bl" it returns "tr", if you pass in "br" it
- * returns "tl", etc.
- */
- OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
- var opp = "";
-
- opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
- opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
-
- return opp;
- };
- /* ======================================================================
- OpenLayers/BaseTypes/Element.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Util.js
- * @requires OpenLayers/BaseTypes.js
- */
- /**
- * Namespace: OpenLayers.Element
- */
- OpenLayers.Element = {
- /**
- * APIFunction: visible
- *
- * Parameters:
- * element - {DOMElement}
- *
- * Returns:
- * {Boolean} Is the element visible?
- */
- visible: function(element) {
- return OpenLayers.Util.getElement(element).style.display != 'none';
- },
- /**
- * APIFunction: toggle
- * Toggle the visibility of element(s) passed in
- *
- * Parameters:
- * element - {DOMElement} Actually user can pass any number of elements
- */
- toggle: function() {
- for (var i=0, len=arguments.length; i<len; i++) {
- var element = OpenLayers.Util.getElement(arguments[i]);
- var display = OpenLayers.Element.visible(element) ? 'none'
- : '';
- element.style.display = display;
- }
- },
- /**
- * APIFunction: remove
- * Remove the specified element from the DOM.
- *
- * Parameters:
- * element - {DOMElement}
- */
- remove: function(element) {
- element = OpenLayers.Util.getElement(element);
- element.parentNode.removeChild(element);
- },
- /**
- * APIFunction: getHeight
- *
- * Parameters:
- * element - {DOMElement}
- *
- * Returns:
- * {Integer} The offset height of the element passed in
- */
- getHeight: function(element) {
- element = OpenLayers.Util.getElement(element);
- return element.offsetHeight;
- },
- /**
- * Function: hasClass
- * Tests if an element has the given CSS class name.
- *
- * Parameters:
- * element - {DOMElement} A DOM element node.
- * name - {String} The CSS class name to search for.
- *
- * Returns:
- * {Boolean} The element has the given class name.
- */
- hasClass: function(element, name) {
- var names = element.className;
- return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names));
- },
-
- /**
- * Function: addClass
- * Add a CSS class name to an element. Safe where element already has
- * the class name.
- *
- * Parameters:
- * element - {DOMElement} A DOM element node.
- * name - {String} The CSS class name to add.
- *
- * Returns:
- * {DOMElement} The element.
- */
- addClass: function(element, name) {
- if(!OpenLayers.Element.hasClass(element, name)) {
- element.className += (element.className ? " " : "") + name;
- }
- return element;
- },
- /**
- * Function: removeClass
- * Remove a CSS class name from an element. Safe where element does not
- * have the class name.
- *
- * Parameters:
- * element - {DOMElement} A DOM element node.
- * name - {String} The CSS class name to remove.
- *
- * Returns:
- * {DOMElement} The element.
- */
- removeClass: function(element, name) {
- var names = element.className;
- if(names) {
- element.className = OpenLayers.String.trim(
- names.replace(
- new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " "
- )
- );
- }
- return element;
- },
- /**
- * Function: toggleClass
- * Remove a CSS class name from an element if it exists. Add the class name
- * if it doesn't exist.
- *
- * Parameters:
- * element - {DOMElement} A DOM element node.
- * name - {String} The CSS class name to toggle.
- *
- * Returns:
- * {DOMElement} The element.
- */
- toggleClass: function(element, name) {
- if(OpenLayers.Element.hasClass(element, name)) {
- OpenLayers.Element.removeClass(element, name);
- } else {
- OpenLayers.Element.addClass(element, name);
- }
- return element;
- },
- /**
- * APIFunction: getStyle
- *
- * Parameters:
- * element - {DOMElement}
- * style - {?}
- *
- * Returns:
- * {?}
- */
- getStyle: function(element, style) {
- element = OpenLayers.Util.getElement(element);
- var value = null;
- if (element && element.style) {
- value = element.style[OpenLayers.String.camelize(style)];
- if (!value) {
- if (document.defaultView &&
- document.defaultView.getComputedStyle) {
-
- var css = document.defaultView.getComputedStyle(element, null);
- value = css ? css.getPropertyValue(style) : null;
- } else if (element.currentStyle) {
- value = element.currentStyle[OpenLayers.String.camelize(style)];
- }
- }
-
- var positions = ['left', 'top', 'right', 'bottom'];
- if (window.opera &&
- (OpenLayers.Util.indexOf(positions,style) != -1) &&
- (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
- value = 'auto';
- }
- }
-
- return value == 'auto' ? null : value;
- }
- };
- /* ======================================================================
- OpenLayers/BaseTypes/LonLat.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Class: OpenLayers.LonLat
- * This class represents a longitude and latitude pair
- */
- OpenLayers.LonLat = OpenLayers.Class({
- /**
- * APIProperty: lon
- * {Float} The x-axis coodinate in map units
- */
- lon: 0.0,
-
- /**
- * APIProperty: lat
- * {Float} The y-axis coordinate in map units
- */
- lat: 0.0,
- /**
- * Constructor: OpenLayers.LonLat
- * Create a new map location. Coordinates can be passed either as two
- * arguments, or as a single argument.
- *
- * Parameters (two arguments):
- * lon - {Number} The x-axis coordinate in map units. If your map is in
- * a geographic projection, this will be the Longitude. Otherwise,
- * it will be the x coordinate of the map location in your map units.
- * lat - {Number} The y-axis coordinate in map units. If your map is in
- * a geographic projection, this will be the Latitude. Otherwise,
- * it will be the y coordinate of the map location in your map units.
- *
- * Parameters (single argument):
- * location - {Array(Float)} [lon, lat]
- */
- initialize: function(lon, lat) {
- if (OpenLayers.Util.isArray(lon)) {
- lat = lon[1];
- lon = lon[0];
- }
- this.lon = OpenLayers.Util.toFloat(lon);
- this.lat = OpenLayers.Util.toFloat(lat);
- },
-
- /**
- * Method: toString
- * Return a readable string version of the lonlat
- *
- * Returns:
- * {String} String representation of OpenLayers.LonLat object.
- * (e.g. <i>"lon=5,lat=42"</i>)
- */
- toString:function() {
- return ("lon=" + this.lon + ",lat=" + this.lat);
- },
- /**
- * APIMethod: toShortString
- *
- * Returns:
- * {String} Shortened String representation of OpenLayers.LonLat object.
- * (e.g. <i>"5, 42"</i>)
- */
- toShortString:function() {
- return (this.lon + ", " + this.lat);
- },
- /**
- * APIMethod: clone
- *
- * Returns:
- * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon
- * and lat values
- */
- clone:function() {
- return new OpenLayers.LonLat(this.lon, this.lat);
- },
- /**
- * APIMethod: add
- *
- * Parameters:
- * lon - {Float}
- * lat - {Float}
- *
- * Returns:
- * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and
- * lat passed-in added to this's.
- */
- add:function(lon, lat) {
- if ( (lon == null) || (lat == null) ) {
- throw new TypeError('LonLat.add cannot receive null values');
- }
- return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon),
- this.lat + OpenLayers.Util.toFloat(lat));
- },
- /**
- * APIMethod: equals
- *
- * Parameters:
- * ll - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {Boolean} Boolean value indicating whether the passed-in
- * <OpenLayers.LonLat> object has the same lon and lat
- * components as this.
- * Note: if ll passed in is null, returns false
- */
- equals:function(ll) {
- var equals = false;
- if (ll != null) {
- equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
- (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
- }
- return equals;
- },
- /**
- * APIMethod: transform
- * Transform the LonLat object from source to dest. This transformation is
- * *in place*: if you want a *new* lonlat, use .clone() first.
- *
- * Parameters:
- * source - {<OpenLayers.Projection>} Source projection.
- * dest - {<OpenLayers.Projection>} Destination projection.
- *
- * Returns:
- * {<OpenLayers.LonLat>} Itself, for use in chaining operations.
- */
- transform: function(source, dest) {
- var point = OpenLayers.Projection.transform(
- {'x': this.lon, 'y': this.lat}, source, dest);
- this.lon = point.x;
- this.lat = point.y;
- return this;
- },
-
- /**
- * APIMethod: wrapDateLine
- *
- * Parameters:
- * maxExtent - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the
- * "dateline" (as specified by the borders of
- * maxExtent)
- */
- wrapDateLine: function(maxExtent) {
- var newLonLat = this.clone();
-
- if (maxExtent) {
- //shift right?
- while (newLonLat.lon < maxExtent.left) {
- newLonLat.lon += maxExtent.getWidth();
- }
-
- //shift left?
- while (newLonLat.lon > maxExtent.right) {
- newLonLat.lon -= maxExtent.getWidth();
- }
- }
-
- return newLonLat;
- },
- CLASS_NAME: "OpenLayers.LonLat"
- });
- /**
- * Function: fromString
- * Alternative constructor that builds a new <OpenLayers.LonLat> from a
- * parameter string
- *
- * Parameters:
- * str - {String} Comma-separated Lon,Lat coordinate string.
- * (e.g. <i>"5,40"</i>)
- *
- * Returns:
- * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
- * passed-in String.
- */
- OpenLayers.LonLat.fromString = function(str) {
- var pair = str.split(",");
- return new OpenLayers.LonLat(pair[0], pair[1]);
- };
- /**
- * Function: fromArray
- * Alternative constructor that builds a new <OpenLayers.LonLat> from an
- * array of two numbers that represent lon- and lat-values.
- *
- * Parameters:
- * arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42])
- *
- * Returns:
- * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
- * passed-in array.
- */
- OpenLayers.LonLat.fromArray = function(arr) {
- var gotArr = OpenLayers.Util.isArray(arr),
- lon = gotArr && arr[0],
- lat = gotArr && arr[1];
- return new OpenLayers.LonLat(lon, lat);
- };
- /* ======================================================================
- OpenLayers/BaseTypes/Pixel.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Class: OpenLayers.Pixel
- * This class represents a screen coordinate, in x and y coordinates
- */
- OpenLayers.Pixel = OpenLayers.Class({
-
- /**
- * APIProperty: x
- * {Number} The x coordinate
- */
- x: 0.0,
- /**
- * APIProperty: y
- * {Number} The y coordinate
- */
- y: 0.0,
-
- /**
- * Constructor: OpenLayers.Pixel
- * Create a new OpenLayers.Pixel instance
- *
- * Parameters:
- * x - {Number} The x coordinate
- * y - {Number} The y coordinate
- *
- * Returns:
- * An instance of OpenLayers.Pixel
- */
- initialize: function(x, y) {
- this.x = parseFloat(x);
- this.y = parseFloat(y);
- },
-
- /**
- * Method: toString
- * Cast this object into a string
- *
- * Returns:
- * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
- */
- toString:function() {
- return ("x=" + this.x + ",y=" + this.y);
- },
- /**
- * APIMethod: clone
- * Return a clone of this pixel object
- *
- * Returns:
- * {<OpenLayers.Pixel>} A clone pixel
- */
- clone:function() {
- return new OpenLayers.Pixel(this.x, this.y);
- },
-
- /**
- * APIMethod: equals
- * Determine whether one pixel is equivalent to another
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- *
- * Returns:
- * {Boolean} The point passed in as parameter is equal to this. Note that
- * if px passed in is null, returns false.
- */
- equals:function(px) {
- var equals = false;
- if (px != null) {
- equals = ((this.x == px.x && this.y == px.y) ||
- (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
- }
- return equals;
- },
- /**
- * APIMethod: distanceTo
- * Returns the distance to the pixel point passed in as a parameter.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {Float} The pixel point passed in as parameter to calculate the
- * distance to.
- */
- distanceTo:function(px) {
- return Math.sqrt(
- Math.pow(this.x - px.x, 2) +
- Math.pow(this.y - px.y, 2)
- );
- },
- /**
- * APIMethod: add
- *
- * Parameters:
- * x - {Integer}
- * y - {Integer}
- *
- * Returns:
- * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
- * values passed in.
- */
- add:function(x, y) {
- if ( (x == null) || (y == null) ) {
- throw new TypeError('Pixel.add cannot receive null values');
- }
- return new OpenLayers.Pixel(this.x + x, this.y + y);
- },
- /**
- * APIMethod: offset
- *
- * Parameters
- * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- *
- * Returns:
- * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
- * x&y values of the pixel passed in.
- */
- offset:function(px) {
- var newPx = this.clone();
- if (px) {
- newPx = this.add(px.x, px.y);
- }
- return newPx;
- },
- CLASS_NAME: "OpenLayers.Pixel"
- });
- /* ======================================================================
- OpenLayers/BaseTypes/Size.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Class: OpenLayers.Size
- * Instances of this class represent a width/height pair
- */
- OpenLayers.Size = OpenLayers.Class({
- /**
- * APIProperty: w
- * {Number} width
- */
- w: 0.0,
-
- /**
- * APIProperty: h
- * {Number} height
- */
- h: 0.0,
- /**
- * Constructor: OpenLayers.Size
- * Create an instance of OpenLayers.Size
- *
- * Parameters:
- * w - {Number} width
- * h - {Number} height
- */
- initialize: function(w, h) {
- this.w = parseFloat(w);
- this.h = parseFloat(h);
- },
- /**
- * Method: toString
- * Return the string representation of a size object
- *
- * Returns:
- * {String} The string representation of OpenLayers.Size object.
- * (e.g. <i>"w=55,h=66"</i>)
- */
- toString:function() {
- return ("w=" + this.w + ",h=" + this.h);
- },
- /**
- * APIMethod: clone
- * Create a clone of this size object
- *
- * Returns:
- * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
- * values
- */
- clone:function() {
- return new OpenLayers.Size(this.w, this.h);
- },
- /**
- *
- * APIMethod: equals
- * Determine where this size is equal to another
- *
- * Parameters:
- * sz - {<OpenLayers.Size>|Object} An OpenLayers.Size or an object with
- * a 'w' and 'h' properties.
- *
- * Returns:
- * {Boolean} The passed in size has the same h and w properties as this one.
- * Note that if sz passed in is null, returns false.
- */
- equals:function(sz) {
- var equals = false;
- if (sz != null) {
- equals = ((this.w == sz.w && this.h == sz.h) ||
- (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
- }
- return equals;
- },
- CLASS_NAME: "OpenLayers.Size"
- });
- /* ======================================================================
- OpenLayers/Console.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Namespace: OpenLayers.Console
- * The OpenLayers.Console namespace is used for debugging and error logging.
- * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
- * calls to OpenLayers.Console methods will get redirected to window.console.
- * This makes use of the Firebug extension where available and allows for
- * cross-browser debugging Firebug style.
- *
- * Note:
- * Note that behavior will differ with the Firebug extention and Firebug Lite.
- * Most notably, the Firebug Lite console does not currently allow for
- * hyperlinks to code or for clicking on object to explore their properties.
- *
- */
- OpenLayers.Console = {
- /**
- * Create empty functions for all console methods. The real value of these
- * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
- * included. We explicitly require the Firebug Lite script to trigger
- * functionality of the OpenLayers.Console methods.
- */
-
- /**
- * APIFunction: log
- * Log an object in the console. The Firebug Lite console logs string
- * representation of objects. Given multiple arguments, they will
- * be cast to strings and logged with a space delimiter. If the first
- * argument is a string with printf-like formatting, subsequent arguments
- * will be used in string substitution. Any additional arguments (beyond
- * the number substituted in a format string) will be appended in a space-
- * delimited line.
- *
- * Parameters:
- * object - {Object}
- */
- log: function() {},
- /**
- * APIFunction: debug
- * Writes a message to the console, including a hyperlink to the line
- * where it was called.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- debug: function() {},
- /**
- * APIFunction: info
- * Writes a message to the console with the visual "info" icon and color
- * coding and a hyperlink to the line where it was called.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- info: function() {},
- /**
- * APIFunction: warn
- * Writes a message to the console with the visual "warning" icon and
- * color coding and a hyperlink to the line where it was called.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- warn: function() {},
- /**
- * APIFunction: error
- * Writes a message to the console with the visual "error" icon and color
- * coding and a hyperlink to the line where it was called.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- error: function() {},
-
- /**
- * APIFunction: userError
- * A single interface for showing error messages to the user. The default
- * behavior is a Javascript alert, though this can be overridden by
- * reassigning OpenLayers.Console.userError to a different function.
- *
- * Expects a single error message
- *
- * Parameters:
- * error - {Object}
- */
- userError: function(error) {
- alert(error);
- },
- /**
- * APIFunction: assert
- * Tests that an expression is true. If not, it will write a message to
- * the console and throw an exception.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- assert: function() {},
- /**
- * APIFunction: dir
- * Prints an interactive listing of all properties of the object. This
- * looks identical to the view that you would see in the DOM tab.
- *
- * Parameters:
- * object - {Object}
- */
- dir: function() {},
- /**
- * APIFunction: dirxml
- * Prints the XML source tree of an HTML or XML element. This looks
- * identical to the view that you would see in the HTML tab. You can click
- * on any node to inspect it in the HTML tab.
- *
- * Parameters:
- * object - {Object}
- */
- dirxml: function() {},
- /**
- * APIFunction: trace
- * Prints an interactive stack trace of JavaScript execution at the point
- * where it is called. The stack trace details the functions on the stack,
- * as well as the values that were passed as arguments to each function.
- * You can click each function to take you to its source in the Script tab,
- * and click each argument value to inspect it in the DOM or HTML tabs.
- *
- */
- trace: function() {},
- /**
- * APIFunction: group
- * Writes a message to the console and opens a nested block to indent all
- * future messages sent to the console. Call OpenLayers.Console.groupEnd()
- * to close the block.
- *
- * May be called with multiple arguments as with OpenLayers.Console.log().
- *
- * Parameters:
- * object - {Object}
- */
- group: function() {},
- /**
- * APIFunction: groupEnd
- * Closes the most recently opened block created by a call to
- * OpenLayers.Console.group
- */
- groupEnd: function() {},
-
- /**
- * APIFunction: time
- * Creates a new timer under the given name. Call
- * OpenLayers.Console.timeEnd(name)
- * with the same name to stop the timer and print the time elapsed.
- *
- * Parameters:
- * name - {String}
- */
- time: function() {},
- /**
- * APIFunction: timeEnd
- * Stops a timer created by a call to OpenLayers.Console.time(name) and
- * writes the time elapsed.
- *
- * Parameters:
- * name - {String}
- */
- timeEnd: function() {},
- /**
- * APIFunction: profile
- * Turns on the JavaScript profiler. The optional argument title would
- * contain the text to be printed in the header of the profile report.
- *
- * This function is not currently implemented in Firebug Lite.
- *
- * Parameters:
- * title - {String} Optional title for the profiler
- */
- profile: function() {},
- /**
- * APIFunction: profileEnd
- * Turns off the JavaScript profiler and prints its report.
- *
- * This function is not currently implemented in Firebug Lite.
- */
- profileEnd: function() {},
- /**
- * APIFunction: count
- * Writes the number of times that the line of code where count was called
- * was executed. The optional argument title will print a message in
- * addition to the number of the count.
- *
- * This function is not currently implemented in Firebug Lite.
- *
- * Parameters:
- * title - {String} Optional title to be printed with count
- */
- count: function() {},
- CLASS_NAME: "OpenLayers.Console"
- };
- /**
- * Execute an anonymous function to extend the OpenLayers.Console namespace
- * if the firebug.js script is included. This closure is used so that the
- * "scripts" and "i" variables don't pollute the global namespace.
- */
- (function() {
- /**
- * If Firebug Lite is included (before this script), re-route all
- * OpenLayers.Console calls to the console object.
- */
- var scripts = document.getElementsByTagName("script");
- for(var i=0, len=scripts.length; i<len; ++i) {
- if(scripts[i].src.indexOf("firebug.js") != -1) {
- if(console) {
- OpenLayers.Util.extend(OpenLayers.Console, console);
- break;
- }
- }
- }
- })();
- /* ======================================================================
- OpenLayers/Lang.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Console.js
- */
- /**
- * Namespace: OpenLayers.Lang
- * Internationalization namespace. Contains dictionaries in various languages
- * and methods to set and get the current language.
- */
- OpenLayers.Lang = {
-
- /**
- * Property: code
- * {String} Current language code to use in OpenLayers. Use the
- * <setCode> method to set this value and the <getCode> method to
- * retrieve it.
- */
- code: null,
- /**
- * APIProperty: defaultCode
- * {String} Default language to use when a specific language can't be
- * found. Default is "en".
- */
- defaultCode: "en",
-
- /**
- * APIFunction: getCode
- * Get the current language code.
- *
- * Returns:
- * {String} The current language code.
- */
- getCode: function() {
- if(!OpenLayers.Lang.code) {
- OpenLayers.Lang.setCode();
- }
- return OpenLayers.Lang.code;
- },
-
- /**
- * APIFunction: setCode
- * Set the language code for string translation. This code is used by
- * the <OpenLayers.Lang.translate> method.
- *
- * Parameters:
- * code - {String} These codes follow the IETF recommendations at
- * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the
- * browser's language setting will be tested. If no <OpenLayers.Lang>
- * dictionary exists for the code, the <OpenLayers.String.defaultLang>
- * will be used.
- */
- setCode: function(code) {
- var lang;
- if(!code) {
- code = (OpenLayers.BROWSER_NAME == "msie") ?
- navigator.userLanguage : navigator.language;
- }
- var parts = code.split('-');
- parts[0] = parts[0].toLowerCase();
- if(typeof OpenLayers.Lang[parts[0]] == "object") {
- lang = parts[0];
- }
- // check for regional extensions
- if(parts[1]) {
- var testLang = parts[0] + '-' + parts[1].toUpperCase();
- if(typeof OpenLayers.Lang[testLang] == "object") {
- lang = testLang;
- }
- }
- if(!lang) {
- OpenLayers.Console.warn(
- 'Failed to find OpenLayers.Lang.' + parts.join("-") +
- ' dictionary, falling back to default language'
- );
- lang = OpenLayers.Lang.defaultCode;
- }
-
- OpenLayers.Lang.code = lang;
- },
- /**
- * APIMethod: translate
- * Looks up a key from a dictionary based on the current language string.
- * The value of <getCode> will be used to determine the appropriate
- * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
- *
- * Parameters:
- * key - {String} The key for an i18n string value in the dictionary.
- * context - {Object} Optional context to be used with
- * <OpenLayers.String.format>.
- *
- * Returns:
- * {String} A internationalized string.
- */
- translate: function(key, context) {
- var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
- var message = dictionary && dictionary[key];
- if(!message) {
- // Message not found, fall back to message key
- message = key;
- }
- if(context) {
- message = OpenLayers.String.format(message, context);
- }
- return message;
- }
-
- };
- /**
- * APIMethod: OpenLayers.i18n
- * Alias for <OpenLayers.Lang.translate>. Looks up a key from a dictionary
- * based on the current language string. The value of
- * <OpenLayers.Lang.getCode> will be used to determine the appropriate
- * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
- *
- * Parameters:
- * key - {String} The key for an i18n string value in the dictionary.
- * context - {Object} Optional context to be used with
- * <OpenLayers.String.format>.
- *
- * Returns:
- * {String} A internationalized string.
- */
- OpenLayers.i18n = OpenLayers.Lang.translate;
- /* ======================================================================
- OpenLayers/Util.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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<len; i++) {
- var element = arguments[i];
- if (typeof element == 'string') {
- element = document.getElementById(element);
- }
- if (arguments.length == 1) {
- return element;
- }
- elements.push(element);
- }
- return elements;
- };
- /**
- * Function: isElement
- * A cross-browser implementation of "e instanceof Element".
- *
- * Parameters:
- * o - {Object} The object to test.
- *
- * Returns:
- * {Boolean}
- */
- OpenLayers.Util.isElement = function(o) {
- return !!(o && o.nodeType === 1);
- };
- /**
- * Function: isArray
- * Tests that the provided object is an array.
- * This test handles the cross-IFRAME case not caught
- * by "a instanceof Array" and should be used instead.
- *
- * Parameters:
- * a - {Object} the object test.
- *
- * Returns:
- * {Boolean} true if the object is an array.
- */
- OpenLayers.Util.isArray = function(a) {
- return (Object.prototype.toString.call(a) === '[object Array]');
- };
- /**
- * Maintain existing definition of $.
- */
- if(typeof window.$ === "undefined") {
- window.$ = OpenLayers.Util.getElement;
- }
- /**
- * Function: removeItem
- * Remove an object from an array. Iterates through the array
- * to find the item, then removes it.
- *
- * Parameters:
- * array - {Array}
- * item - {Object}
- *
- * Returns:
- * {Array} A reference to the array
- */
- OpenLayers.Util.removeItem = function(array, item) {
- for(var i = array.length - 1; 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;
- }
- };
- /**
- * 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.
- * px - {<OpenLayers.Pixel>|Object} The element left and top position,
- * OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- * sz - {<OpenLayers.Size>|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;
- }
- 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.
- * px - {<OpenLayers.Pixel>|Object} The element left and top position,
- * OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- * sz - {<OpenLayers.Size>|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 - {<OpenLayers.Pixel>|Object} The element left and top position,
- * OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- * sz - {<OpenLayers.Size>|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 - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- * sz - {<OpenLayers.Size>|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 - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- * sz - {<OpenLayers.Size>|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. <i>"key1=value1&key2=value2&key3=value3"</i>)
- * 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<len; itemIndex++) {
- item = value[itemIndex];
- encodedItemArray.push(encodeURIComponent(
- (item === null || item === undefined) ? "" : item)
- );
- }
- encodedValue = encodedItemArray.join(",");
- }
- else {
- /* value is a string; simply encode */
- encodedValue = encodeURIComponent(value);
- }
- paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
- }
- }
-
- return paramsArray.join("&");
- };
- /**
- * Function: urlAppend
- * Appends a parameter string to a url. This function includes the logic for
- * using the appropriate character (none, & or ?) to append to the url before
- * appending the param string.
- *
- * Parameters:
- * url - {String} The url to append to
- * paramStr - {String} The param string to append
- *
- * Returns:
- * {String} The new url
- */
- OpenLayers.Util.urlAppend = function(url, paramStr) {
- var newUrl = url;
- if(paramStr) {
- var parts = (url + " ").split(/[?&]/);
- newUrl += (parts.pop() === " " ?
- paramStr :
- parts.length ? "&" + paramStr : "?" + paramStr);
- }
- return newUrl;
- };
- /**
- * Function: getImagesLocation
- *
- * Returns:
- * {String} The fully formatted image location string
- */
- OpenLayers.Util.getImagesLocation = function() {
- return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
- };
- /**
- * Function: getImageLocation
- *
- * Returns:
- * {String} The fully formatted location string for a specified image
- */
- OpenLayers.Util.getImageLocation = function(image) {
- return OpenLayers.Util.getImagesLocation() + image;
- };
- /**
- * Function: Try
- * Execute functions until one of them doesn't throw an error.
- * Capitalized because "try" is a reserved word in JavaScript.
- * Taken directly from OpenLayers.Util.Try()
- *
- * Parameters:
- * [*] - {Function} Any number of parameters may be passed to Try()
- * It will attempt to execute each of them until one of them
- * successfully executes.
- * If none executes successfully, returns null.
- *
- * Returns:
- * {*} The value returned by the first successfully executed function.
- */
- OpenLayers.Util.Try = function() {
- var returnValue = null;
- for (var i=0, len=arguments.length; i<len; i++) {
- var lambda = arguments[i];
- try {
- returnValue = lambda();
- break;
- } catch (e) {}
- }
- return returnValue;
- };
- /**
- * Function: getXmlNodeValue
- *
- * Parameters:
- * node - {XMLNode}
- *
- * Returns:
- * {String} The text value of the given node, without breaking in firefox or IE
- */
- OpenLayers.Util.getXmlNodeValue = function(node) {
- var val = null;
- OpenLayers.Util.Try(
- function() {
- val = node.text;
- if (!val) {
- val = node.textContent;
- }
- if (!val) {
- val = node.firstChild.nodeValue;
- }
- },
- function() {
- val = node.textContent;
- });
- return val;
- };
- /**
- * Function: mouseLeft
- *
- * Parameters:
- * evt - {Event}
- * div - {HTMLDivElement}
- *
- * Returns:
- * {Boolean}
- */
- OpenLayers.Util.mouseLeft = function (evt, div) {
- // start with the element to which the mouse has moved
- var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
- // walk up the DOM tree.
- while (target != div && target != null) {
- target = target.parentNode;
- }
- // if the target we stop at isn't the div, then we've left the div.
- return (target != div);
- };
- /**
- * Property: precision
- * {Number} The number of significant digits to retain to avoid
- * floating point precision errors.
- *
- * We use 14 as a "safe" default because, although IEEE 754 double floats
- * (standard on most modern operating systems) support up to about 16
- * significant digits, 14 significant digits are sufficient to represent
- * sub-millimeter accuracy in any coordinate system that anyone is likely to
- * use with OpenLayers.
- *
- * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
- * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
- * with certain projections, e.g. spherical Mercator.
- *
- */
- OpenLayers.Util.DEFAULT_PRECISION = 14;
- /**
- * Function: toFloat
- * Convenience method to cast an object to a Number, rounded to the
- * desired floating point precision.
- *
- * Parameters:
- * number - {Number} The number to cast and round.
- * precision - {Number} An integer suitable for use with
- * Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
- * If set to 0, no rounding is performed.
- *
- * Returns:
- * {Number} The cast, rounded number.
- */
- OpenLayers.Util.toFloat = function (number, precision) {
- if (precision == null) {
- precision = OpenLayers.Util.DEFAULT_PRECISION;
- }
- if (typeof number !== "number") {
- number = parseFloat(number);
- }
- return precision === 0 ? number :
- parseFloat(number.toPrecision(precision));
- };
- /**
- * Function: rad
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
- OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
- /**
- * Function: deg
- *
- * Parameters:
- * x - {Float}
- *
- * Returns:
- * {Float}
- */
- OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
- /**
- * Property: VincentyConstants
- * {Object} Constants for Vincenty functions.
- */
- OpenLayers.Util.VincentyConstants = {
- a: 6378137,
- b: 6356752.3142,
- f: 1/298.257223563
- };
- /**
- * APIFunction: distVincenty
- * Given two objects representing points with geographic coordinates, this
- * calculates the distance between those points on the surface of an
- * ellipsoid.
- *
- * Parameters:
- * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
- * p2 - {<OpenLayers.LonLat>} (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 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
- * properties) The start point.
- * brng - {Float} The bearing (degrees).
- * dist - {Float} The ground distance (meters).
- *
- * Returns:
- * {<OpenLayers.LonLat>} 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.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
- OpenLayers.Util.getParameters = function(url) {
- // 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<len; ++i) {
- var keyValue = pairs[i].split('=');
- if (keyValue[0]) {
- var key = keyValue[0];
- try {
- key = decodeURIComponent(key);
- } catch (err) {
- key = unescape(key);
- }
-
- // being liberal by replacing "+" with " "
- var value = (keyValue[1] || '').replace(/\+/g, " ");
- try {
- value = decodeURIComponent(value);
- } catch (err) {
- value = unescape(value);
- }
-
- // follow OGC convention of comma delimited values
- value = value.split(",");
- //if there's only one value, do not return as array
- if (value.length == 1) {
- value = value[0];
- }
-
- parameters[key] = value;
- }
- }
- return parameters;
- };
- /**
- * Property: lastSeqID
- * {Integer} The ever-incrementing count variable.
- * Used for generating unique ids.
- */
- OpenLayers.Util.lastSeqID = 0;
- /**
- * Function: createUniqueID
- * Create a unique identifier for this session. Each time this function
- * is called, a counter is incremented. The return will be the optional
- * prefix (defaults to "id_") appended with the counter value.
- *
- * Parameters:
- * prefix - {String} Optional string to prefix unique id. Default is "id_".
- *
- * Returns:
- * {String} A unique id string, built on the passed in prefix.
- */
- OpenLayers.Util.createUniqueID = function(prefix) {
- if (prefix == null) {
- prefix = "id_";
- }
- OpenLayers.Util.lastSeqID += 1;
- return prefix + OpenLayers.Util.lastSeqID;
- };
- /**
- * Constant: INCHES_PER_UNIT
- * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
- * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
- * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
- * and PROJ.4 (http://trac.osgeo.org/proj/)
- * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
- * The hardcoded table of PROJ.4 units are in pj_units.c.
- */
- OpenLayers.INCHES_PER_UNIT = {
- 'inches': 1.0,
- 'ft': 12.0,
- 'mi': 63360.0,
- 'm': 39.3701,
- 'km': 39370.1,
- 'dd': 4374754,
- 'yd': 36
- };
- OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
- OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
- OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
- // Units from CS-Map
- OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
- OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
- "Inch": OpenLayers.INCHES_PER_UNIT.inches,
- "Meter": 1.0 / OpenLayers.METERS_PER_INCH, //EPSG:9001
- "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH, //EPSG:9003
- "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9002
- "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH, //EPSG:9005
- "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH, //EPSG:9041
- "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH, //EPSG:9094
- "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
- "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
- "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
- "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9036
- "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
- "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH, //EPSG:9040
- "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH, //EPSG:9084
- "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH, //EPSG:9085
- "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH, //EPSG:9086
- "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH, //EPSG:9087
- "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH, //EPSG:9080
- "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH, //EPSG:9081
- "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH, //EPSG:9082
- "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH, //EPSG:9083
- "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
- "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9096
- "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9093
- "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9030
- "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
- "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
- "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
- "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH, //EPSG:9031
- "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
- "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9038
- "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9033
- "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9062
- "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9042
- "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9039
- "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9034
- "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9063
- "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9043
- "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH, //EPSG:9097
- "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH, //EPSG:9098
- "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
- "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
- "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
- "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
- "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
- "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
- "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
- "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
- "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
- "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
- });
- //unit abbreviations supported by PROJ.4
- OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
- "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
- "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
- "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
- "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
- "kmi": OpenLayers.INCHES_PER_UNIT["nmi"], //International Nautical Mile
- "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
- "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"], //International Chain
- "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
- "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
- "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot
- "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard
- "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
- "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"], //U.S. Surveyor's Statute Mile
- "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"], //Indian Yard
- "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"], //Indian Foot
- "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH //Indian Chain
- });
- /**
- * Constant: DOTS_PER_INCH
- * {Integer} 72 (A sensible default)
- */
- OpenLayers.DOTS_PER_INCH = 72;
- /**
- * Function: normalizeScale
- *
- * Parameters:
- * scale - {float}
- *
- * Returns:
- * {Float} A normalized scale value, in 1 / X format.
- * This means that if a value less than one ( already 1/x) is passed
- * in, it just returns scale directly. Otherwise, it returns
- * 1 / scale
- */
- OpenLayers.Util.normalizeScale = function (scale) {
- var normScale = (scale > 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 = 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;
- }
- }
- 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
- });
- 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 (#).
- *
- * 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);
- // 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 - {<OpenLayers.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.Size>}
- */
- 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<l; i++) {
- if (!content.childNodes[i].style) continue;
- content.childNodes[i].style.overflow = "visible";
- }
- }
-
- // add content to restricted container
- container.appendChild(content);
-
- // append container to body for rendering
- if (superContainer) {
- containerElement.appendChild(superContainer);
- } else {
- containerElement.appendChild(container);
- }
-
- // calculate scroll width of content and add corners and shadow width
- if (!w) {
- w = parseInt(content.scrollWidth);
-
- // update container width to allow height to adjust
- container.style.width = w + "px";
- }
- // capture height and add shadow and corner image widths
- if (!h) {
- h = parseInt(content.scrollHeight);
- }
- // remove elements
- container.removeChild(content);
- if (superContainer) {
- superContainer.removeChild(container);
- containerElement.removeChild(superContainer);
- } else {
- containerElement.removeChild(container);
- }
-
- return new OpenLayers.Size(w, h);
- };
- /**
- * APIFunction: getScrollbarWidth
- * This function has been modified by the OpenLayers from the original version,
- * written by Matthew Eernisse and released under the Apache 2
- * license here:
- *
- * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
- *
- * It has been modified simply to cache its value, since it is physically
- * impossible that this code could ever run in more than one browser at
- * once.
- *
- * Returns:
- * {Integer}
- */
- OpenLayers.Util.getScrollbarWidth = function() {
-
- var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
-
- if (scrollbarWidth == null) {
- var scr = null;
- var inn = null;
- var wNoScroll = 0;
- var wScroll = 0;
-
- // Outer scrolling div
- scr = document.createElement('div');
- scr.style.position = 'absolute';
- scr.style.top = '-1000px';
- scr.style.left = '-1000px';
- scr.style.width = '100px';
- scr.style.height = '50px';
- // Start with no scrollbar
- scr.style.overflow = 'hidden';
-
- // Inner content div
- inn = document.createElement('div');
- inn.style.width = '100%';
- inn.style.height = '200px';
-
- // Put the inner div in the scrolling div
- scr.appendChild(inn);
- // Append the scrolling div to the doc
- document.body.appendChild(scr);
-
- // Width of the inner div sans scrollbar
- wNoScroll = inn.offsetWidth;
-
- // Add the scrollbar
- scr.style.overflow = 'scroll';
- // Width of the inner div width scrollbar
- wScroll = inn.offsetWidth;
-
- // Remove the scrolling div from the doc
- document.body.removeChild(document.body.lastChild);
-
- // Pixel width of the scroller
- OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
- scrollbarWidth = OpenLayers.Util._scrollbarWidth;
- }
- return scrollbarWidth;
- };
- /**
- * APIFunction: getFormattedLonLat
- * This function will return latitude or longitude value formatted as
- *
- * Parameters:
- * coordinate - {Float} the coordinate value to be formatted
- * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
- * to be formatted (default = lat)
- * dmsOption - {String} specify the precision of the output can be one of:
- * 'dms' show degrees minutes and seconds
- * 'dm' show only degrees and minutes
- * 'd' show only degrees
- *
- * Returns:
- * {String} the coordinate value formatted as a string
- */
- OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
- if (!dmsOption) {
- dmsOption = 'dms'; //default to show degree, minutes, seconds
- }
-
- coordinate = (coordinate+540)%360 - 180; // normalize for sphere being round
-
- var abscoordinate = Math.abs(coordinate);
- var coordinatedegrees = Math.floor(abscoordinate);
- var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
- var tempcoordinateminutes = coordinateminutes;
- coordinateminutes = Math.floor(coordinateminutes);
- var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
- coordinateseconds = Math.round(coordinateseconds*10);
- coordinateseconds /= 10;
- if( coordinateseconds >= 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;
- };
- /* ======================================================================
- OpenLayers/Format.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Util.js
- */
- /**
- * Class: OpenLayers.Format
- * Base class for format reading/writing a variety of formats. Subclasses
- * of OpenLayers.Format are expected to have read and write methods.
- */
- OpenLayers.Format = OpenLayers.Class({
-
- /**
- * Property: options
- * {Object} A reference to options passed to the constructor.
- */
- options: null,
-
- /**
- * APIProperty: externalProjection
- * {<OpenLayers.Projection>} When passed a externalProjection and
- * internalProjection, the format will reproject the geometries it
- * reads or writes. The externalProjection is the projection used by
- * the content which is passed into read or which comes out of write.
- * In order to reproject, a projection transformation function for the
- * specified projections must be available. This support may be
- * provided via proj4js or via a custom transformation function. See
- * {<OpenLayers.Projection.addTransform>} for more information on
- * custom transformations.
- */
- externalProjection: null,
- /**
- * APIProperty: internalProjection
- * {<OpenLayers.Projection>} When passed a externalProjection and
- * internalProjection, the format will reproject the geometries it
- * reads or writes. The internalProjection is the projection used by
- * the geometries which are returned by read or which are passed into
- * write. In order to reproject, a projection transformation function
- * for the specified projections must be available. This support may be
- * provided via proj4js or via a custom transformation function. See
- * {<OpenLayers.Projection.addTransform>} for more information on
- * custom transformations.
- */
- internalProjection: null,
- /**
- * APIProperty: data
- * {Object} When <keepData> is true, this is the parsed string sent to
- * <read>.
- */
- data: null,
- /**
- * APIProperty: keepData
- * {Object} Maintain a reference (<data>) to the most recently read data.
- * Default is false.
- */
- keepData: false,
- /**
- * Constructor: OpenLayers.Format
- * Instances of this class are not useful. See one of the subclasses.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * format
- *
- * Valid options:
- * keepData - {Boolean} If true, upon <read>, the data property will be
- * set to the parsed object (e.g. the json or xml object).
- *
- * Returns:
- * An instance of OpenLayers.Format
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- this.options = options;
- },
-
- /**
- * APIMethod: destroy
- * Clean up.
- */
- destroy: function() {
- },
- /**
- * Method: read
- * Read data from a string, and return an object whose type depends on the
- * subclass.
- *
- * Parameters:
- * data - {string} Data to read/parse.
- *
- * Returns:
- * Depends on the subclass
- */
- read: function(data) {
- throw new Error('Read not implemented.');
- },
-
- /**
- * Method: write
- * Accept an object, and return a string.
- *
- * Parameters:
- * object - {Object} Object to be serialized
- *
- * Returns:
- * {String} A string representation of the object.
- */
- write: function(object) {
- throw new Error('Write not implemented.');
- },
- CLASS_NAME: "OpenLayers.Format"
- });
- /* ======================================================================
- OpenLayers/Format/CSWGetRecords.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format.js
- */
- /**
- * Class: OpenLayers.Format.CSWGetRecords
- * Default version is 2.0.2.
- *
- * Returns:
- * {<OpenLayers.Format>} A CSWGetRecords format of the given version.
- */
- OpenLayers.Format.CSWGetRecords = function(options) {
- options = OpenLayers.Util.applyDefaults(
- options, OpenLayers.Format.CSWGetRecords.DEFAULTS
- );
- var cls = OpenLayers.Format.CSWGetRecords["v"+options.version.replace(/\./g, "_")];
- if(!cls) {
- throw "Unsupported CSWGetRecords version: " + options.version;
- }
- return new cls(options);
- };
- /**
- * Constant: DEFAULTS
- * {Object} Default properties for the CSWGetRecords format.
- */
- OpenLayers.Format.CSWGetRecords.DEFAULTS = {
- "version": "2.0.2"
- };
- /* ======================================================================
- OpenLayers/Control.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- */
- /**
- * Class: OpenLayers.Control
- * Controls affect the display or behavior of the map. They allow everything
- * from panning and zooming to displaying a scale indicator. Controls by
- * default are added to the map they are contained within however it is
- * possible to add a control to an external div by passing the div in the
- * options parameter.
- *
- * Example:
- * The following example shows how to add many of the common controls
- * to a map.
- *
- * > var map = new OpenLayers.Map('map', { controls: [] });
- * >
- * > map.addControl(new OpenLayers.Control.PanZoomBar());
- * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
- * > map.addControl(new OpenLayers.Control.Permalink());
- * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
- * > map.addControl(new OpenLayers.Control.MousePosition());
- * > map.addControl(new OpenLayers.Control.OverviewMap());
- * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
- *
- * The next code fragment is a quick example of how to intercept
- * shift-mouse click to display the extent of the bounding box
- * dragged out by the user. Usually controls are not created
- * in exactly this manner. See the source for a more complete
- * example:
- *
- * > var control = new OpenLayers.Control();
- * > OpenLayers.Util.extend(control, {
- * > draw: function () {
- * > // this Handler.Box will intercept the shift-mousedown
- * > // before Control.MouseDefault gets to see it
- * > this.box = new OpenLayers.Handler.Box( control,
- * > {"done": this.notice},
- * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
- * > this.box.activate();
- * > },
- * >
- * > notice: function (bounds) {
- * > OpenLayers.Console.userError(bounds);
- * > }
- * > });
- * > map.addControl(control);
- *
- */
- OpenLayers.Control = OpenLayers.Class({
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} this gets set in the addControl() function in
- * OpenLayers.Map
- */
- map: null,
- /**
- * APIProperty: div
- * {DOMElement} The element that contains the control, if not present the
- * control is placed inside the map.
- */
- div: null,
- /**
- * APIProperty: type
- * {Number} Controls can have a 'type'. The type determines the type of
- * interactions which are possible with them when they are placed in an
- * <OpenLayers.Control.Panel>.
- */
- type: null,
- /**
- * Property: allowSelection
- * {Boolean} By default, controls do not allow selection, because
- * it may interfere with map dragging. If this is true, OpenLayers
- * will not prevent selection of the control.
- * Default is false.
- */
- allowSelection: false,
- /**
- * Property: displayClass
- * {string} This property is used for CSS related to the drawing of the
- * Control.
- */
- displayClass: "",
-
- /**
- * APIProperty: title
- * {string} This property is used for showing a tooltip over the
- * Control.
- */
- title: "",
- /**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * false.
- */
- autoActivate: false,
- /**
- * APIProperty: active
- * {Boolean} The control is active (read-only). Use <activate> and
- * <deactivate> to change control state.
- */
- active: null,
- /**
- * Property: handler
- * {<OpenLayers.Handler>} null
- */
- handler: null,
- /**
- * APIProperty: eventListeners
- * {Object} If set as an option at construction, the eventListeners
- * object will be registered with <OpenLayers.Events.on>. Object
- * structure must be a listeners object as shown in the example for
- * the events.on method.
- */
- eventListeners: null,
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} Events instance for listeners and triggering
- * control specific events.
- *
- * Register a listener for a particular event with the following syntax:
- * (code)
- * control.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * All event objects have at least the following properties:
- * object - {Object} A reference to control.events.object (a reference
- * to the control).
- * element - {DOMElement} A reference to control.events.element (which
- * will be null unless documented otherwise).
- *
- * Supported map event types:
- * activate - Triggered when activated.
- * deactivate - Triggered when deactivated.
- */
- events: null,
- /**
- * Constructor: OpenLayers.Control
- * Create an OpenLayers Control. The options passed as a parameter
- * directly extend the control. For example passing the following:
- *
- * > var control = new OpenLayers.Control({div: myDiv});
- *
- * Overrides the default div attribute value of null.
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function (options) {
- // We do this before the extend so that instances can override
- // className in options.
- this.displayClass =
- this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
-
- OpenLayers.Util.extend(this, options);
-
- this.events = new OpenLayers.Events(this);
- if(this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
- }
- if (this.id == null) {
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- }
- },
- /**
- * Method: destroy
- * The destroy method is used to perform any clean up before the control
- * is dereferenced. Typically this is where event listeners are removed
- * to prevent memory leaks.
- */
- destroy: function () {
- if(this.events) {
- if(this.eventListeners) {
- this.events.un(this.eventListeners);
- }
- this.events.destroy();
- this.events = null;
- }
- this.eventListeners = null;
- // eliminate circular references
- if (this.handler) {
- this.handler.destroy();
- this.handler = null;
- }
- if(this.handlers) {
- for(var key in this.handlers) {
- if(this.handlers.hasOwnProperty(key) &&
- typeof this.handlers[key].destroy == "function") {
- this.handlers[key].destroy();
- }
- }
- this.handlers = null;
- }
- if (this.map) {
- this.map.removeControl(this);
- this.map = null;
- }
- this.div = null;
- },
- /**
- * Method: setMap
- * Set the map property for the control. This is done through an accessor
- * so that subclasses can override this and take special action once
- * they have their map variable set.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- this.map = map;
- if (this.handler) {
- this.handler.setMap(map);
- }
- },
-
- /**
- * Method: draw
- * The draw method is called when the control is ready to be displayed
- * on the page. If a div has not been created one is created. Controls
- * with a visual component will almost always want to override this method
- * to customize the look of control.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
- * or null.
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the control
- */
- draw: function (px) {
- if (this.div == null) {
- this.div = OpenLayers.Util.createDiv(this.id);
- this.div.className = this.displayClass;
- if (!this.allowSelection) {
- this.div.className += " olControlNoSelect";
- this.div.setAttribute("unselectable", "on", 0);
- this.div.onselectstart = OpenLayers.Function.False;
- }
- if (this.title != "") {
- this.div.title = this.title;
- }
- }
- if (px != null) {
- this.position = px.clone();
- }
- this.moveTo(this.position);
- return this.div;
- },
- /**
- * Method: moveTo
- * Sets the left and top style attributes to the passed in pixel
- * coordinates.
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- */
- moveTo: function (px) {
- if ((px != null) && (this.div != null)) {
- this.div.style.left = px.x + "px";
- this.div.style.top = px.y + "px";
- }
- },
- /**
- * APIMethod: activate
- * Explicitly activates a control and it's associated
- * handler if one has been set. Controls can be
- * deactivated by calling the deactivate() method.
- *
- * Returns:
- * {Boolean} True if the control was successfully activated or
- * false if the control was already active.
- */
- activate: function () {
- if (this.active) {
- return false;
- }
- if (this.handler) {
- this.handler.activate();
- }
- this.active = true;
- if(this.map) {
- OpenLayers.Element.addClass(
- this.map.viewPortDiv,
- this.displayClass.replace(/ /g, "") + "Active"
- );
- }
- this.events.triggerEvent("activate");
- return true;
- },
-
- /**
- * APIMethod: deactivate
- * Deactivates a control and it's associated handler if any. The exact
- * effect of this depends on the control itself.
- *
- * Returns:
- * {Boolean} True if the control was effectively deactivated or false
- * if the control was already inactive.
- */
- deactivate: function () {
- if (this.active) {
- if (this.handler) {
- this.handler.deactivate();
- }
- this.active = false;
- if(this.map) {
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv,
- this.displayClass.replace(/ /g, "") + "Active"
- );
- }
- this.events.triggerEvent("deactivate");
- return true;
- }
- return false;
- },
- CLASS_NAME: "OpenLayers.Control"
- });
- /**
- * Constant: OpenLayers.Control.TYPE_BUTTON
- */
- OpenLayers.Control.TYPE_BUTTON = 1;
- /**
- * Constant: OpenLayers.Control.TYPE_TOGGLE
- */
- OpenLayers.Control.TYPE_TOGGLE = 2;
- /**
- * Constant: OpenLayers.Control.TYPE_TOOL
- */
- OpenLayers.Control.TYPE_TOOL = 3;
- /* ======================================================================
- OpenLayers/Events.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Util.js
- */
- /**
- * Namespace: OpenLayers.Event
- * Utility functions for event handling.
- */
- OpenLayers.Event = {
- /**
- * Property: observers
- * {Object} A hashtable cache of the event observers. Keyed by
- * element._eventCacheID
- */
- observers: false,
- /**
- * Constant: KEY_SPACE
- * {int}
- */
- KEY_SPACE: 32,
-
- /**
- * Constant: KEY_BACKSPACE
- * {int}
- */
- KEY_BACKSPACE: 8,
- /**
- * Constant: KEY_TAB
- * {int}
- */
- KEY_TAB: 9,
- /**
- * Constant: KEY_RETURN
- * {int}
- */
- KEY_RETURN: 13,
- /**
- * Constant: KEY_ESC
- * {int}
- */
- KEY_ESC: 27,
- /**
- * Constant: KEY_LEFT
- * {int}
- */
- KEY_LEFT: 37,
- /**
- * Constant: KEY_UP
- * {int}
- */
- KEY_UP: 38,
- /**
- * Constant: KEY_RIGHT
- * {int}
- */
- KEY_RIGHT: 39,
- /**
- * Constant: KEY_DOWN
- * {int}
- */
- KEY_DOWN: 40,
- /**
- * Constant: KEY_DELETE
- * {int}
- */
- KEY_DELETE: 46,
- /**
- * Method: element
- * Cross browser event element detection.
- *
- * Parameters:
- * event - {Event}
- *
- * Returns:
- * {DOMElement} The element that caused the event
- */
- element: function(event) {
- return event.target || event.srcElement;
- },
- /**
- * Method: isSingleTouch
- * Determine whether event was caused by a single touch
- *
- * Parameters:
- * event - {Event}
- *
- * Returns:
- * {Boolean}
- */
- isSingleTouch: function(event) {
- return event.touches && event.touches.length == 1;
- },
- /**
- * Method: isMultiTouch
- * Determine whether event was caused by a multi touch
- *
- * Parameters:
- * event - {Event}
- *
- * Returns:
- * {Boolean}
- */
- isMultiTouch: function(event) {
- return event.touches && event.touches.length > 1;
- },
- /**
- * Method: isLeftClick
- * Determine whether event was caused by a left click.
- *
- * Parameters:
- * event - {Event}
- *
- * Returns:
- * {Boolean}
- */
- isLeftClick: function(event) {
- return (((event.which) && (event.which == 1)) ||
- ((event.button) && (event.button == 1)));
- },
- /**
- * Method: isRightClick
- * Determine whether event was caused by a right mouse click.
- *
- * Parameters:
- * event - {Event}
- *
- * Returns:
- * {Boolean}
- */
- isRightClick: function(event) {
- return (((event.which) && (event.which == 3)) ||
- ((event.button) && (event.button == 2)));
- },
-
- /**
- * Method: stop
- * Stops an event from propagating.
- *
- * Parameters:
- * event - {Event}
- * allowDefault - {Boolean} If true, we stop the event chain but
- * still allow the default browser behaviour (text selection,
- * radio-button clicking, etc). Default is false.
- */
- stop: function(event, allowDefault) {
-
- if (!allowDefault) {
- if (event.preventDefault) {
- event.preventDefault();
- } else {
- event.returnValue = false;
- }
- }
-
- if (event.stopPropagation) {
- event.stopPropagation();
- } else {
- event.cancelBubble = true;
- }
- },
- /**
- * Method: findElement
- *
- * Parameters:
- * event - {Event}
- * tagName - {String}
- *
- * Returns:
- * {DOMElement} The first node with the given tagName, starting from the
- * node the event was triggered on and traversing the DOM upwards
- */
- findElement: function(event, tagName) {
- var element = OpenLayers.Event.element(event);
- while (element.parentNode && (!element.tagName ||
- (element.tagName.toUpperCase() != tagName.toUpperCase()))){
- element = element.parentNode;
- }
- return element;
- },
- /**
- * Method: observe
- *
- * Parameters:
- * elementParam - {DOMElement || String}
- * name - {String}
- * observer - {function}
- * useCapture - {Boolean}
- */
- observe: function(elementParam, name, observer, useCapture) {
- var element = OpenLayers.Util.getElement(elementParam);
- useCapture = useCapture || false;
- if (name == 'keypress' &&
- (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
- || element.attachEvent)) {
- name = 'keydown';
- }
- //if observers cache has not yet been created, create it
- if (!this.observers) {
- this.observers = {};
- }
- //if not already assigned, make a new unique cache ID
- if (!element._eventCacheID) {
- var idPrefix = "eventCacheID_";
- if (element.id) {
- idPrefix = element.id + "_" + idPrefix;
- }
- element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
- }
- var cacheID = element._eventCacheID;
- //if there is not yet a hash entry for this element, add one
- if (!this.observers[cacheID]) {
- this.observers[cacheID] = [];
- }
- //add a new observer to this element's list
- this.observers[cacheID].push({
- 'element': element,
- 'name': name,
- 'observer': observer,
- 'useCapture': useCapture
- });
- //add the actual browser event listener
- if (element.addEventListener) {
- element.addEventListener(name, observer, useCapture);
- } else if (element.attachEvent) {
- element.attachEvent('on' + name, observer);
- }
- },
- /**
- * Method: stopObservingElement
- * Given the id of an element to stop observing, cycle through the
- * element's cached observers, calling stopObserving on each one,
- * skipping those entries which can no longer be removed.
- *
- * parameters:
- * elementParam - {DOMElement || String}
- */
- stopObservingElement: function(elementParam) {
- var element = OpenLayers.Util.getElement(elementParam);
- var cacheID = element._eventCacheID;
- this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
- },
- /**
- * Method: _removeElementObservers
- *
- * Parameters:
- * elementObservers - {Array(Object)} Array of (element, name,
- * observer, usecapture) objects,
- * taken directly from hashtable
- */
- _removeElementObservers: function(elementObservers) {
- if (elementObservers) {
- for(var i = elementObservers.length-1; i >= 0; i--) {
- var entry = elementObservers[i];
- var args = new Array(entry.element,
- entry.name,
- entry.observer,
- entry.useCapture);
- var removed = OpenLayers.Event.stopObserving.apply(this, args);
- }
- }
- },
- /**
- * Method: stopObserving
- *
- * Parameters:
- * elementParam - {DOMElement || String}
- * name - {String}
- * observer - {function}
- * useCapture - {Boolean}
- *
- * Returns:
- * {Boolean} Whether or not the event observer was removed
- */
- stopObserving: function(elementParam, name, observer, useCapture) {
- useCapture = useCapture || false;
-
- var element = OpenLayers.Util.getElement(elementParam);
- var cacheID = element._eventCacheID;
- if (name == 'keypress') {
- if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||
- element.detachEvent) {
- name = 'keydown';
- }
- }
- // find element's entry in this.observers cache and remove it
- var foundEntry = false;
- var elementObservers = OpenLayers.Event.observers[cacheID];
- if (elementObservers) {
-
- // find the specific event type in the element's list
- var i=0;
- while(!foundEntry && i < elementObservers.length) {
- var cacheEntry = elementObservers[i];
-
- if ((cacheEntry.name == name) &&
- (cacheEntry.observer == observer) &&
- (cacheEntry.useCapture == useCapture)) {
-
- elementObservers.splice(i, 1);
- if (elementObservers.length == 0) {
- delete OpenLayers.Event.observers[cacheID];
- }
- foundEntry = true;
- break;
- }
- i++;
- }
- }
-
- //actually remove the event listener from browser
- if (foundEntry) {
- if (element.removeEventListener) {
- element.removeEventListener(name, observer, useCapture);
- } else if (element && element.detachEvent) {
- element.detachEvent('on' + name, observer);
- }
- }
- return foundEntry;
- },
-
- /**
- * Method: unloadCache
- * Cycle through all the element entries in the events cache and call
- * stopObservingElement on each.
- */
- unloadCache: function() {
- // check for OpenLayers.Event before checking for observers, because
- // OpenLayers.Event may be undefined in IE if no map instance was
- // created
- if (OpenLayers.Event && OpenLayers.Event.observers) {
- for (var cacheID in OpenLayers.Event.observers) {
- var elementObservers = OpenLayers.Event.observers[cacheID];
- OpenLayers.Event._removeElementObservers.apply(this,
- [elementObservers]);
- }
- OpenLayers.Event.observers = false;
- }
- },
- CLASS_NAME: "OpenLayers.Event"
- };
- /* prevent memory leaks in IE */
- OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
- /**
- * Class: OpenLayers.Events
- */
- OpenLayers.Events = OpenLayers.Class({
- /**
- * Constant: BROWSER_EVENTS
- * {Array(String)} supported events
- */
- BROWSER_EVENTS: [
- "mouseover", "mouseout",
- "mousedown", "mouseup", "mousemove",
- "click", "dblclick", "rightclick", "dblrightclick",
- "resize", "focus", "blur",
- "touchstart", "touchmove", "touchend",
- "keydown"
- ],
- /**
- * Property: listeners
- * {Object} Hashtable of Array(Function): events listener functions
- */
- listeners: null,
- /**
- * Property: object
- * {Object} the code object issuing application events
- */
- object: null,
- /**
- * Property: element
- * {DOMElement} the DOM element receiving browser events
- */
- element: null,
- /**
- * Property: eventHandler
- * {Function} bound event handler attached to elements
- */
- eventHandler: null,
- /**
- * APIProperty: fallThrough
- * {Boolean}
- */
- fallThrough: null,
- /**
- * APIProperty: includeXY
- * {Boolean} Should the .xy property automatically be created for browser
- * mouse events? In general, this should be false. If it is true, then
- * mouse events will automatically generate a '.xy' property on the
- * event object that is passed. (Prior to OpenLayers 2.7, this was true
- * by default.) Otherwise, you can call the getMousePosition on the
- * relevant events handler on the object available via the 'evt.object'
- * property of the evt object. So, for most events, you can call:
- * function named(evt) {
- * this.xy = this.object.events.getMousePosition(evt)
- * }
- *
- * This option typically defaults to false for performance reasons:
- * when creating an events object whose primary purpose is to manage
- * relatively positioned mouse events within a div, it may make
- * sense to set it to true.
- *
- * This option is also used to control whether the events object caches
- * offsets. If this is false, it will not: the reason for this is that
- * it is only expected to be called many times if the includeXY property
- * is set to true. If you set this to true, you are expected to clear
- * the offset cache manually (using this.clearMouseCache()) if:
- * the border of the element changes
- * the location of the element in the page changes
- */
- includeXY: false,
-
- /**
- * APIProperty: extensions
- * {Object} Event extensions registered with this instance. Keys are
- * event types, values are {OpenLayers.Events.*} extension instances or
- * {Boolean} for events that an instantiated extension provides in
- * addition to the one it was created for.
- *
- * Extensions create an event in addition to browser events, which usually
- * fires when a sequence of browser events is completed. Extensions are
- * automatically instantiated when a listener is registered for an event
- * provided by an extension.
- *
- * Extensions are created in the <OpenLayers.Events> namespace using
- * <OpenLayers.Class>, and named after the event they provide.
- * The constructor receives the target <OpenLayers.Events> instance as
- * argument. Extensions that need to capture browser events before they
- * propagate can register their listeners events using <register>, with
- * {extension: true} as 4th argument.
- *
- * If an extension creates more than one event, an alias for each event
- * type should be created and reference the same class. The constructor
- * should set a reference in the target's extensions registry to itself.
- *
- * Below is a minimal extension that provides the "foostart" and "fooend"
- * event types, which replace the native "click" event type if clicked on
- * an element with the css class "foo":
- *
- * (code)
- * OpenLayers.Events.foostart = OpenLayers.Class({
- * initialize: function(target) {
- * this.target = target;
- * this.target.register("click", this, this.doStuff, {extension: true});
- * // only required if extension provides more than one event type
- * this.target.extensions["foostart"] = true;
- * this.target.extensions["fooend"] = true;
- * },
- * destroy: function() {
- * var target = this.target;
- * target.unregister("click", this, this.doStuff);
- * delete this.target;
- * // only required if extension provides more than one event type
- * delete target.extensions["foostart"];
- * delete target.extensions["fooend"];
- * },
- * doStuff: function(evt) {
- * var propagate = true;
- * if (OpenLayers.Event.element(evt).className === "foo") {
- * propagate = false;
- * var target = this.target;
- * target.triggerEvent("foostart");
- * window.setTimeout(function() {
- * target.triggerEvent("fooend");
- * }, 1000);
- * }
- * return propagate;
- * }
- * });
- * // only required if extension provides more than one event type
- * OpenLayers.Events.fooend = OpenLayers.Events.foostart;
- * (end)
- *
- */
- extensions: null,
-
- /**
- * Property: extensionCount
- * {Object} Keys are event types (like in <listeners>), values are the
- * number of extension listeners for each event type.
- */
- extensionCount: null,
- /**
- * Method: clearMouseListener
- * A version of <clearMouseCache> that is bound to this instance so that
- * it can be used with <OpenLayers.Event.observe> and
- * <OpenLayers.Event.stopObserving>.
- */
- clearMouseListener: null,
- /**
- * Constructor: OpenLayers.Events
- * Construct an OpenLayers.Events object.
- *
- * Parameters:
- * object - {Object} The js object to which this Events object is being added
- * element - {DOMElement} A dom element to respond to browser events
- * eventTypes - {Array(String)} Deprecated. Array of custom application
- * events. A listener may be registered for any named event, regardless
- * of the values provided here.
- * fallThrough - {Boolean} Allow events to fall through after these have
- * been handled?
- * options - {Object} Options for the events object.
- */
- initialize: function (object, element, eventTypes, fallThrough, options) {
- OpenLayers.Util.extend(this, options);
- this.object = object;
- this.fallThrough = fallThrough;
- this.listeners = {};
- this.extensions = {};
- this.extensionCount = {};
-
- // if a dom element is specified, add a listeners list
- // for browser events on the element and register them
- if (element != null) {
- this.attachToElement(element);
- }
- },
- /**
- * APIMethod: destroy
- */
- destroy: function () {
- for (var e in this.extensions) {
- if (typeof this.extensions[e] !== "boolean") {
- this.extensions[e].destroy();
- }
- }
- this.extensions = null;
- if (this.element) {
- OpenLayers.Event.stopObservingElement(this.element);
- if(this.element.hasScrollEvent) {
- OpenLayers.Event.stopObserving(
- window, "scroll", this.clearMouseListener
- );
- }
- }
- this.element = null;
- this.listeners = null;
- this.object = null;
- this.fallThrough = null;
- this.eventHandler = null;
- },
- /**
- * APIMethod: addEventType
- * Deprecated. Any event can be triggered without adding it first.
- *
- * Parameters:
- * eventName - {String}
- */
- addEventType: function(eventName) {
- },
- /**
- * Method: attachToElement
- *
- * Parameters:
- * element - {HTMLDOMElement} a DOM element to attach browser events to
- */
- attachToElement: function (element) {
- if (this.element) {
- OpenLayers.Event.stopObservingElement(this.element);
- } else {
- // keep a bound copy of handleBrowserEvent() so that we can
- // pass the same function to both Event.observe() and .stopObserving()
- this.eventHandler = OpenLayers.Function.bindAsEventListener(
- this.handleBrowserEvent, this
- );
-
- // to be used with observe and stopObserving
- this.clearMouseListener = OpenLayers.Function.bind(
- this.clearMouseCache, this
- );
- }
- this.element = element;
- for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) {
- // register the event cross-browser
- OpenLayers.Event.observe(
- element, this.BROWSER_EVENTS[i], this.eventHandler
- );
- }
- // disable dragstart in IE so that mousedown/move/up works normally
- OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
- },
-
- /**
- * APIMethod: on
- * Convenience method for registering listeners with a common scope.
- * Internally, this method calls <register> as shown in the examples
- * below.
- *
- * Example use:
- * (code)
- * // register a single listener for the "loadstart" event
- * events.on({"loadstart": loadStartListener});
- *
- * // this is equivalent to the following
- * events.register("loadstart", undefined, loadStartListener);
- *
- * // register multiple listeners to be called with the same `this` object
- * events.on({
- * "loadstart": loadStartListener,
- * "loadend": loadEndListener,
- * scope: object
- * });
- *
- * // this is equivalent to the following
- * events.register("loadstart", object, loadStartListener);
- * events.register("loadend", object, loadEndListener);
- * (end)
- *
- * Parameters:
- * object - {Object}
- */
- on: function(object) {
- for(var type in object) {
- if(type != "scope" && object.hasOwnProperty(type)) {
- this.register(type, object.scope, object[type]);
- }
- }
- },
- /**
- * APIMethod: register
- * Register an event on the events object.
- *
- * When the event is triggered, the 'func' function will be called, in the
- * context of 'obj'. Imagine we were to register an event, specifying an
- * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the
- * context in the callback function will be our Bounds object. This means
- * that within our callback function, we can access the properties and
- * methods of the Bounds object through the "this" variable. So our
- * callback could execute something like:
- * : leftStr = "Left: " + this.left;
- *
- * or
- *
- * : centerStr = "Center: " + this.getCenterLonLat();
- *
- * Parameters:
- * type - {String} Name of the event to register
- * obj - {Object} The object to bind the context to for the callback#.
- * If no object is specified, default is the Events's 'object' property.
- * func - {Function} The callback function. If no callback is
- * specified, this function does nothing.
- * priority - {Boolean|Object} If true, adds the new listener to the
- * *front* of the events queue instead of to the end.
- *
- * Valid options for priority:
- * extension - {Boolean} If true, then the event will be registered as
- * extension event. Extension events are handled before all other
- * events.
- */
- register: function (type, obj, func, priority) {
- if (type in OpenLayers.Events && !this.extensions[type]) {
- this.extensions[type] = new OpenLayers.Events[type](this);
- }
- if (func != null) {
- if (obj == null) {
- obj = this.object;
- }
- var listeners = this.listeners[type];
- if (!listeners) {
- listeners = [];
- this.listeners[type] = listeners;
- this.extensionCount[type] = 0;
- }
- var listener = {obj: obj, func: func};
- if (priority) {
- listeners.splice(this.extensionCount[type], 0, listener);
- if (typeof priority === "object" && priority.extension) {
- this.extensionCount[type]++;
- }
- } else {
- listeners.push(listener);
- }
- }
- },
- /**
- * APIMethod: registerPriority
- * Same as register() but adds the new listener to the *front* of the
- * events queue instead of to the end.
- *
- * TODO: get rid of this in 3.0 - Decide whether listeners should be
- * called in the order they were registered or in reverse order.
- *
- *
- * Parameters:
- * type - {String} Name of the event to register
- * obj - {Object} The object to bind the context to for the callback#.
- * If no object is specified, default is the Events's
- * 'object' property.
- * func - {Function} The callback function. If no callback is
- * specified, this function does nothing.
- */
- registerPriority: function (type, obj, func) {
- this.register(type, obj, func, true);
- },
-
- /**
- * APIMethod: un
- * Convenience method for unregistering listeners with a common scope.
- * Internally, this method calls <unregister> as shown in the examples
- * below.
- *
- * Example use:
- * (code)
- * // unregister a single listener for the "loadstart" event
- * events.un({"loadstart": loadStartListener});
- *
- * // this is equivalent to the following
- * events.unregister("loadstart", undefined, loadStartListener);
- *
- * // unregister multiple listeners with the same `this` object
- * events.un({
- * "loadstart": loadStartListener,
- * "loadend": loadEndListener,
- * scope: object
- * });
- *
- * // this is equivalent to the following
- * events.unregister("loadstart", object, loadStartListener);
- * events.unregister("loadend", object, loadEndListener);
- * (end)
- */
- un: function(object) {
- for(var type in object) {
- if(type != "scope" && object.hasOwnProperty(type)) {
- this.unregister(type, object.scope, object[type]);
- }
- }
- },
- /**
- * APIMethod: unregister
- *
- * Parameters:
- * type - {String}
- * obj - {Object} If none specified, defaults to this.object
- * func - {Function}
- */
- unregister: function (type, obj, func) {
- if (obj == null) {
- obj = this.object;
- }
- var listeners = this.listeners[type];
- if (listeners != null) {
- for (var i=0, len=listeners.length; i<len; i++) {
- if (listeners[i].obj == obj && listeners[i].func == func) {
- listeners.splice(i, 1);
- break;
- }
- }
- }
- },
- /**
- * Method: remove
- * Remove all listeners for a given event type. If type is not registered,
- * does nothing.
- *
- * Parameters:
- * type - {String}
- */
- remove: function(type) {
- if (this.listeners[type] != null) {
- this.listeners[type] = [];
- }
- },
- /**
- * APIMethod: triggerEvent
- * Trigger a specified registered event.
- *
- * Parameters:
- * type - {String}
- * evt - {Event}
- *
- * Returns:
- * {Boolean} The last listener return. If a listener returns false, the
- * chain of listeners will stop getting called.
- */
- triggerEvent: function (type, evt) {
- var listeners = this.listeners[type];
- // fast path
- if(!listeners || listeners.length == 0) {
- return undefined;
- }
- // prep evt object with object & div references
- if (evt == null) {
- evt = {};
- }
- evt.object = this.object;
- evt.element = this.element;
- if(!evt.type) {
- evt.type = type;
- }
-
- // execute all callbacks registered for specified type
- // get a clone of the listeners array to
- // allow for splicing during callbacks
- listeners = listeners.slice();
- var continueChain;
- for (var i=0, len=listeners.length; i<len; i++) {
- var callback = listeners[i];
- // bind the context to callback.obj
- continueChain = callback.func.apply(callback.obj, [evt]);
- if ((continueChain != undefined) && (continueChain == false)) {
- // if callback returns false, execute no more callbacks.
- break;
- }
- }
- // don't fall through to other DOM elements
- if (!this.fallThrough) {
- OpenLayers.Event.stop(evt, true);
- }
- return continueChain;
- },
- /**
- * Method: handleBrowserEvent
- * Basically just a wrapper to the triggerEvent() function, but takes
- * care to set a property 'xy' on the event with the current mouse
- * position.
- *
- * Parameters:
- * evt - {Event}
- */
- handleBrowserEvent: function (evt) {
- var type = evt.type, listeners = this.listeners[type];
- if(!listeners || listeners.length == 0) {
- // noone's listening, bail out
- return;
- }
- // add clientX & clientY to all events - corresponds to average x, y
- var touches = evt.touches;
- if (touches && touches[0]) {
- var x = 0;
- var y = 0;
- var num = touches.length;
- var touch;
- for (var i=0; i<num; ++i) {
- touch = touches[i];
- x += touch.clientX;
- y += touch.clientY;
- }
- evt.clientX = x / num;
- evt.clientY = y / num;
- }
- if (this.includeXY) {
- evt.xy = this.getMousePosition(evt);
- }
- this.triggerEvent(type, evt);
- },
- /**
- * APIMethod: clearMouseCache
- * Clear cached data about the mouse position. This should be called any
- * time the element that events are registered on changes position
- * within the page.
- */
- clearMouseCache: function() {
- this.element.scrolls = null;
- this.element.lefttop = null;
- // OpenLayers.Util.pagePosition needs to use
- // element.getBoundingClientRect to correctly calculate the offsets
- // for the iPhone, but once the page is scrolled, getBoundingClientRect
- // returns incorrect offsets. So our best bet is to not invalidate the
- // offsets once we have them, and hope that the page was not scrolled
- // when we did the initial calculation.
- var body = document.body;
- if (body && !((body.scrollTop != 0 || body.scrollLeft != 0) &&
- navigator.userAgent.match(/iPhone/i))) {
- this.element.offsets = null;
- }
- },
- /**
- * Method: getMousePosition
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
- * for offsets
- */
- getMousePosition: function (evt) {
- if (!this.includeXY) {
- this.clearMouseCache();
- } else if (!this.element.hasScrollEvent) {
- OpenLayers.Event.observe(window, "scroll", this.clearMouseListener);
- this.element.hasScrollEvent = true;
- }
-
- if (!this.element.scrolls) {
- var viewportElement = OpenLayers.Util.getViewportElement();
- this.element.scrolls = [
- viewportElement.scrollLeft,
- viewportElement.scrollTop
- ];
- }
- if (!this.element.lefttop) {
- this.element.lefttop = [
- (document.documentElement.clientLeft || 0),
- (document.documentElement.clientTop || 0)
- ];
- }
-
- if (!this.element.offsets) {
- this.element.offsets = OpenLayers.Util.pagePosition(this.element);
- }
- return new OpenLayers.Pixel(
- (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
- - this.element.lefttop[0],
- (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
- - this.element.lefttop[1]
- );
- },
- CLASS_NAME: "OpenLayers.Events"
- });
- /* ======================================================================
- OpenLayers/Events/buttonclick.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Events.js
- */
- /**
- * Class: OpenLayers.Events.buttonclick
- * Extension event type for handling buttons on top of a dom element. This
- * event type fires "buttonclick" on its <target> when a button was
- * clicked. Buttons are detected by the "olButton" class.
- *
- * This event type makes sure that button clicks do not interfere with other
- * events that are registered on the same <element>.
- *
- * Event types provided by this extension:
- * - *buttonclick* Triggered when a button is clicked. Listeners receive an
- * object with a *buttonElement* property referencing the dom element of
- * the clicked button, and an *buttonXY* property with the click position
- * relative to the button.
- */
- OpenLayers.Events.buttonclick = OpenLayers.Class({
-
- /**
- * Property: target
- * {<OpenLayers.Events>} The events instance that the buttonclick event will
- * be triggered on.
- */
- target: null,
-
- /**
- * Property: events
- * {Array} Events to observe and conditionally stop from propagating when
- * an element with the olButton class (or its olAlphaImg child) is
- * clicked.
- */
- events: [
- 'mousedown', 'mouseup', 'click', 'dblclick',
- 'touchstart', 'touchmove', 'touchend', 'keydown'
- ],
-
- /**
- * Property: startRegEx
- * {RegExp} Regular expression to test Event.type for events that start
- * a buttonclick sequence.
- */
- startRegEx: /^mousedown|touchstart$/,
- /**
- * Property: cancelRegEx
- * {RegExp} Regular expression to test Event.type for events that cancel
- * a buttonclick sequence.
- */
- cancelRegEx: /^touchmove$/,
- /**
- * Property: completeRegEx
- * {RegExp} Regular expression to test Event.type for events that complete
- * a buttonclick sequence.
- */
- completeRegEx: /^mouseup|touchend$/,
-
- /**
- * Property: startEvt
- * {Event} The event that started the click sequence
- */
-
- /**
- * Constructor: OpenLayers.Events.buttonclick
- * Construct a buttonclick event type. Applications are not supposed to
- * create instances of this class - they are created on demand by
- * <OpenLayers.Events> instances.
- *
- * Parameters:
- * target - {<OpenLayers.Events>} The events instance that the buttonclick
- * event will be triggered on.
- */
- initialize: function(target) {
- this.target = target;
- for (var i=this.events.length-1; i>=0; --i) {
- this.target.register(this.events[i], this, this.buttonClick, {
- extension: true
- });
- }
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- for (var i=this.events.length-1; i>=0; --i) {
- this.target.unregister(this.events[i], this, this.buttonClick);
- }
- delete this.target;
- },
- /**
- * Method: getPressedButton
- * Get the pressed button, if any. Returns undefined if no button
- * was pressed.
- *
- * Arguments:
- * element - {DOMElement} The event target.
- *
- * Returns:
- * {DOMElement} The button element, or undefined.
- */
- getPressedButton: function(element) {
- var depth = 3, // limit the search depth
- button;
- do {
- if(OpenLayers.Element.hasClass(element, "olButton")) {
- // hit!
- button = element;
- break;
- }
- element = element.parentNode;
- } while(--depth > 0 && element);
- return button;
- },
- /**
- * Method: buttonClick
- * Check if a button was clicked, and fire the buttonclick event
- *
- * Parameters:
- * evt - {Event}
- */
- buttonClick: function(evt) {
- var propagate = true,
- element = OpenLayers.Event.element(evt);
- if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) {
- // was a button pressed?
- var button = this.getPressedButton(element);
- if (button) {
- if (evt.type === "keydown") {
- switch (evt.keyCode) {
- case OpenLayers.Event.KEY_RETURN:
- case OpenLayers.Event.KEY_SPACE:
- this.target.triggerEvent("buttonclick", {
- buttonElement: button
- });
- OpenLayers.Event.stop(evt);
- propagate = false;
- break;
- }
- } else if (this.startEvt) {
- if (this.completeRegEx.test(evt.type)) {
- var pos = OpenLayers.Util.pagePosition(button);
- this.target.triggerEvent("buttonclick", {
- buttonElement: button,
- buttonXY: {
- x: this.startEvt.clientX - pos[0],
- y: this.startEvt.clientY - pos[1]
- }
- });
- }
- if (this.cancelRegEx.test(evt.type)) {
- delete this.startEvt;
- }
- OpenLayers.Event.stop(evt);
- propagate = false;
- }
- if (this.startRegEx.test(evt.type)) {
- this.startEvt = evt;
- OpenLayers.Event.stop(evt);
- propagate = false;
- }
- } else {
- delete this.startEvt;
- }
- }
- return propagate;
- }
-
- });
- /* ======================================================================
- OpenLayers/Control/OverviewMap.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Control.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/Events/buttonclick.js
- */
- /**
- * Class: OpenLayers.Control.OverviewMap
- * The OverMap control creates a small overview map, useful to display the
- * extent of a zoomed map and your main map and provide additional
- * navigation options to the User. By default the overview map is drawn in
- * the lower right corner of the main map. Create a new overview map with the
- * <OpenLayers.Control.OverviewMap> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
- OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
- /**
- * Property: element
- * {DOMElement} The DOM element that contains the overview map
- */
- element: null,
-
- /**
- * APIProperty: ovmap
- * {<OpenLayers.Map>} A reference to the overview map itself.
- */
- ovmap: null,
- /**
- * APIProperty: size
- * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
- * the size of the map itself - the element that contains the map (default
- * class name olControlOverviewMapElement) may have padding or other style
- * attributes added via CSS.
- */
- size: {w: 180, h: 90},
- /**
- * APIProperty: layers
- * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
- * If none are sent at construction, the base layer for the main map is used.
- */
- layers: null,
-
- /**
- * APIProperty: minRectSize
- * {Integer} The minimum width or height (in pixels) of the extent
- * rectangle on the overview map. When the extent rectangle reaches
- * this size, it will be replaced depending on the value of the
- * <minRectDisplayClass> property. Default is 15 pixels.
- */
- minRectSize: 15,
-
- /**
- * APIProperty: minRectDisplayClass
- * {String} Replacement style class name for the extent rectangle when
- * <minRectSize> is reached. This string will be suffixed on to the
- * displayClass. Default is "RectReplacement".
- *
- * Example CSS declaration:
- * (code)
- * .olControlOverviewMapRectReplacement {
- * overflow: hidden;
- * cursor: move;
- * background-image: url("img/overview_replacement.gif");
- * background-repeat: no-repeat;
- * background-position: center;
- * }
- * (end)
- */
- minRectDisplayClass: "RectReplacement",
- /**
- * APIProperty: minRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther out on the overview map.
- */
- minRatio: 8,
- /**
- * APIProperty: maxRatio
- * {Float} The ratio of the overview map resolution to the main map
- * resolution at which to zoom farther in on the overview map.
- */
- maxRatio: 32,
-
- /**
- * APIProperty: mapOptions
- * {Object} An object containing any non-default properties to be sent to
- * the overview map's map constructor. These should include any
- * non-default options that the main map was constructed with.
- */
- mapOptions: null,
- /**
- * APIProperty: autoPan
- * {Boolean} Always pan the overview map, so the extent marker remains in
- * the center. Default is false. If true, when you drag the extent
- * marker, the overview map will update itself so the marker returns
- * to the center.
- */
- autoPan: false,
-
- /**
- * Property: handlers
- * {Object}
- */
- handlers: null,
- /**
- * Property: resolutionFactor
- * {Object}
- */
- resolutionFactor: 1,
- /**
- * APIProperty: maximized
- * {Boolean} Start as maximized (visible). Defaults to false.
- */
- maximized: false,
- /**
- * Constructor: OpenLayers.Control.OverviewMap
- * Create a new overview map
- *
- * Parameters:
- * options - {Object} Properties of this object will be set on the overview
- * map object. Note, to set options on the map object contained in this
- * control, set <mapOptions> as one of the options properties.
- */
- initialize: function(options) {
- this.layers = [];
- this.handlers = {};
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the control
- */
- destroy: function() {
- if (!this.mapDiv) { // we've already been destroyed
- return;
- }
- if (this.handlers.click) {
- this.handlers.click.destroy();
- }
- if (this.handlers.drag) {
- this.handlers.drag.destroy();
- }
- this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle);
- this.extentRectangle = null;
- if (this.rectEvents) {
- this.rectEvents.destroy();
- this.rectEvents = null;
- }
- if (this.ovmap) {
- this.ovmap.destroy();
- this.ovmap = null;
- }
-
- this.element.removeChild(this.mapDiv);
- this.mapDiv = null;
- this.div.removeChild(this.element);
- this.element = null;
- if (this.maximizeDiv) {
- this.div.removeChild(this.maximizeDiv);
- this.maximizeDiv = null;
- }
-
- if (this.minimizeDiv) {
- this.div.removeChild(this.minimizeDiv);
- this.minimizeDiv = null;
- }
- this.map.events.un({
- buttonclick: this.onButtonClick,
- moveend: this.update,
- changebaselayer: this.baseLayerDraw,
- scope: this
- });
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
- /**
- * Method: draw
- * Render the control in the browser.
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- if (this.layers.length === 0) {
- if (this.map.baseLayer) {
- var layer = this.map.baseLayer.clone();
- this.layers = [layer];
- } else {
- this.map.events.register("changebaselayer", this, this.baseLayerDraw);
- return this.div;
- }
- }
- // create overview map DOM elements
- this.element = document.createElement('div');
- this.element.className = this.displayClass + 'Element';
- this.element.style.display = 'none';
- this.mapDiv = document.createElement('div');
- this.mapDiv.style.width = this.size.w + 'px';
- this.mapDiv.style.height = this.size.h + 'px';
- this.mapDiv.style.position = 'relative';
- this.mapDiv.style.overflow = 'hidden';
- this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
-
- this.extentRectangle = document.createElement('div');
- this.extentRectangle.style.position = 'absolute';
- this.extentRectangle.style.zIndex = 1000; //HACK
- this.extentRectangle.className = this.displayClass+'ExtentRectangle';
- this.element.appendChild(this.mapDiv);
- this.div.appendChild(this.element);
- // Optionally add min/max buttons if the control will go in the
- // map viewport.
- if(!this.outsideViewport) {
- this.div.className += " " + this.displayClass + 'Container';
- // maximize button div
- var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');
- this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
- this.displayClass + 'MaximizeButton',
- null,
- null,
- img,
- 'absolute');
- this.maximizeDiv.style.display = 'none';
- this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton';
- this.div.appendChild(this.maximizeDiv);
-
- // minimize button div
- var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');
- this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
- 'OpenLayers_Control_minimizeDiv',
- null,
- null,
- img,
- 'absolute');
- this.minimizeDiv.style.display = 'none';
- this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton';
- this.div.appendChild(this.minimizeDiv);
- this.minimizeControl();
- } else {
- // show the overview map
- this.element.style.display = '';
- }
- if(this.map.getExtent()) {
- this.update();
- }
-
- this.map.events.on({
- buttonclick: this.onButtonClick,
- moveend: this.update,
- scope: this
- });
-
- if (this.maximized) {
- this.maximizeControl();
- }
- return this.div;
- },
-
- /**
- * Method: baseLayerDraw
- * Draw the base layer - called if unable to complete in the initial draw
- */
- baseLayerDraw: function() {
- this.draw();
- this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
- },
- /**
- * Method: rectDrag
- * Handle extent rectangle drag
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The pixel location of the drag.
- */
- rectDrag: function(px) {
- var deltaX = this.handlers.drag.last.x - px.x;
- var deltaY = this.handlers.drag.last.y - px.y;
- if(deltaX != 0 || deltaY != 0) {
- var rectTop = this.rectPxBounds.top;
- var rectLeft = this.rectPxBounds.left;
- var rectHeight = Math.abs(this.rectPxBounds.getHeight());
- var rectWidth = this.rectPxBounds.getWidth();
- // don't allow dragging off of parent element
- var newTop = Math.max(0, (rectTop - deltaY));
- newTop = Math.min(newTop,
- this.ovmap.size.h - this.hComp - rectHeight);
- var newLeft = Math.max(0, (rectLeft - deltaX));
- newLeft = Math.min(newLeft,
- this.ovmap.size.w - this.wComp - rectWidth);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + rectHeight,
- newLeft + rectWidth,
- newTop));
- }
- },
-
- /**
- * Method: mapDivClick
- * Handle browser events
- *
- * Parameters:
- * evt - {<OpenLayers.Event>} evt
- */
- mapDivClick: function(evt) {
- var pxCenter = this.rectPxBounds.getCenterPixel();
- var deltaX = evt.xy.x - pxCenter.x;
- var deltaY = evt.xy.y - pxCenter.y;
- var top = this.rectPxBounds.top;
- var left = this.rectPxBounds.left;
- var height = Math.abs(this.rectPxBounds.getHeight());
- var width = this.rectPxBounds.getWidth();
- var newTop = Math.max(0, (top + deltaY));
- newTop = Math.min(newTop, this.ovmap.size.h - height);
- var newLeft = Math.max(0, (left + deltaX));
- newLeft = Math.min(newLeft, this.ovmap.size.w - width);
- this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
- newTop + height,
- newLeft + width,
- newTop));
- this.updateMapToRect();
- },
-
- /**
- * Method: onButtonClick
- *
- * Parameters:
- * evt - {Event}
- */
- onButtonClick: function(evt) {
- if (evt.buttonElement === this.minimizeDiv) {
- this.minimizeControl();
- } else if (evt.buttonElement === this.maximizeDiv) {
- this.maximizeControl();
- }
- },
- /**
- * Method: maximizeControl
- * Unhide the control. Called when the control is in the map viewport.
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- maximizeControl: function(e) {
- this.element.style.display = '';
- this.showToggle(false);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
- /**
- * Method: minimizeControl
- * Hide all the contents of the control, shrink the size,
- * add the maximize icon
- *
- * Parameters:
- * e - {<OpenLayers.Event>}
- */
- minimizeControl: function(e) {
- this.element.style.display = 'none';
- this.showToggle(true);
- if (e != null) {
- OpenLayers.Event.stop(e);
- }
- },
- /**
- * Method: showToggle
- * Hide/Show the toggle depending on whether the control is minimized
- *
- * Parameters:
- * minimize - {Boolean}
- */
- showToggle: function(minimize) {
- this.maximizeDiv.style.display = minimize ? '' : 'none';
- this.minimizeDiv.style.display = minimize ? 'none' : '';
- },
- /**
- * Method: update
- * Update the overview map after layers move.
- */
- update: function() {
- if(this.ovmap == null) {
- this.createMap();
- }
-
- if(this.autoPan || !this.isSuitableOverview()) {
- this.updateOverview();
- }
-
- // update extent rectangle
- this.updateRectToMap();
- },
-
- /**
- * Method: isSuitableOverview
- * Determines if the overview map is suitable given the extent and
- * resolution of the main map.
- */
- isSuitableOverview: function() {
- var mapExtent = this.map.getExtent();
- var maxExtent = this.map.maxExtent;
- var testExtent = new OpenLayers.Bounds(
- Math.max(mapExtent.left, maxExtent.left),
- Math.max(mapExtent.bottom, maxExtent.bottom),
- Math.min(mapExtent.right, maxExtent.right),
- Math.min(mapExtent.top, maxExtent.top));
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- testExtent = testExtent.transform(
- this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- }
- var resRatio = this.ovmap.getResolution() / this.map.getResolution();
- return ((resRatio > this.minRatio) &&
- (resRatio <= this.maxRatio) &&
- (this.ovmap.getExtent().containsBounds(testExtent)));
- },
-
- /**
- * Method updateOverview
- * Called by <update> if <isSuitableOverview> returns true
- */
- updateOverview: function() {
- var mapRes = this.map.getResolution();
- var targetRes = this.ovmap.getResolution();
- var resRatio = targetRes / mapRes;
- if(resRatio > this.maxRatio) {
- // zoom in overview map
- targetRes = this.minRatio * mapRes;
- } else if(resRatio <= this.minRatio) {
- // zoom out overview map
- targetRes = this.maxRatio * mapRes;
- }
- var center;
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- center = this.map.center.clone();
- center.transform(this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- } else {
- center = this.map.center;
- }
- this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
- targetRes * this.resolutionFactor));
- this.updateRectToMap();
- },
-
- /**
- * Method: createMap
- * Construct the map that this control contains
- */
- createMap: function() {
- // create the overview map
- var options = OpenLayers.Util.extend(
- {controls: [], maxResolution: 'auto',
- fallThrough: false}, this.mapOptions);
- this.ovmap = new OpenLayers.Map(this.mapDiv, options);
- this.ovmap.viewPortDiv.appendChild(this.extentRectangle);
-
- // prevent ovmap from being destroyed when the page unloads, because
- // the OverviewMap control has to do this (and does it).
- OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
-
- this.ovmap.addLayers(this.layers);
- this.ovmap.zoomToMaxExtent();
- // check extent rectangle border width
- this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-left-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-right-width'));
- this.wComp = (this.wComp) ? this.wComp : 2;
- this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-top-width')) +
- parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
- 'border-bottom-width'));
- this.hComp = (this.hComp) ? this.hComp : 2;
- this.handlers.drag = new OpenLayers.Handler.Drag(
- this, {move: this.rectDrag, done: this.updateMapToRect},
- {map: this.ovmap}
- );
- this.handlers.click = new OpenLayers.Handler.Click(
- this, {
- "click": this.mapDivClick
- },{
- "single": true, "double": false,
- "stopSingle": true, "stopDouble": true,
- "pixelTolerance": 1,
- map: this.ovmap
- }
- );
- this.handlers.click.activate();
-
- this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
- null, true);
- this.rectEvents.register("mouseover", this, function(e) {
- if(!this.handlers.drag.active && !this.map.dragging) {
- this.handlers.drag.activate();
- }
- });
- this.rectEvents.register("mouseout", this, function(e) {
- if(!this.handlers.drag.dragging) {
- this.handlers.drag.deactivate();
- }
- });
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- var sourceUnits = this.map.getProjectionObject().getUnits() ||
- this.map.units || this.map.baseLayer.units;
- var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
- this.ovmap.units || this.ovmap.baseLayer.units;
- this.resolutionFactor = sourceUnits && targetUnits ?
- OpenLayers.INCHES_PER_UNIT[sourceUnits] /
- OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
- }
- },
-
- /**
- * Method: updateRectToMap
- * Updates the extent rectangle position and size to match the map extent
- */
- updateRectToMap: function() {
- // If the projections differ we need to reproject
- var bounds;
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- bounds = this.map.getExtent().transform(
- this.map.getProjectionObject(),
- this.ovmap.getProjectionObject() );
- } else {
- bounds = this.map.getExtent();
- }
- var pxBounds = this.getRectBoundsFromMapBounds(bounds);
- if (pxBounds) {
- this.setRectPxBounds(pxBounds);
- }
- },
-
- /**
- * Method: updateMapToRect
- * Updates the map extent to match the extent rectangle position and size
- */
- updateMapToRect: function() {
- var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
- if (this.ovmap.getProjection() != this.map.getProjection()) {
- lonLatBounds = lonLatBounds.transform(
- this.ovmap.getProjectionObject(),
- this.map.getProjectionObject() );
- }
- this.map.panTo(lonLatBounds.getCenterLonLat());
- },
- /**
- * Method: setRectPxBounds
- * Set extent rectangle pixel bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- */
- setRectPxBounds: function(pxBounds) {
- var top = Math.max(pxBounds.top, 0);
- var left = Math.max(pxBounds.left, 0);
- var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
- this.ovmap.size.h - this.hComp);
- var right = Math.min(pxBounds.left + pxBounds.getWidth(),
- this.ovmap.size.w - this.wComp);
- var width = Math.max(right - left, 0);
- var height = Math.max(bottom - top, 0);
- if(width < this.minRectSize || height < this.minRectSize) {
- this.extentRectangle.className = this.displayClass +
- this.minRectDisplayClass;
- var rLeft = left + (width / 2) - (this.minRectSize / 2);
- var rTop = top + (height / 2) - (this.minRectSize / 2);
- this.extentRectangle.style.top = Math.round(rTop) + 'px';
- this.extentRectangle.style.left = Math.round(rLeft) + 'px';
- this.extentRectangle.style.height = this.minRectSize + 'px';
- this.extentRectangle.style.width = this.minRectSize + 'px';
- } else {
- this.extentRectangle.className = this.displayClass +
- 'ExtentRectangle';
- this.extentRectangle.style.top = Math.round(top) + 'px';
- this.extentRectangle.style.left = Math.round(left) + 'px';
- this.extentRectangle.style.height = Math.round(height) + 'px';
- this.extentRectangle.style.width = Math.round(width) + 'px';
- }
- this.rectPxBounds = new OpenLayers.Bounds(
- Math.round(left), Math.round(bottom),
- Math.round(right), Math.round(top)
- );
- },
- /**
- * Method: getRectBoundsFromMapBounds
- * Get the rect bounds from the map bounds.
- *
- * Parameters:
- * lonLatBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
- * translated into pixel bounds for the overview map
- */
- getRectBoundsFromMapBounds: function(lonLatBounds) {
- var leftBottomPx = this.getOverviewPxFromLonLat({
- lon: lonLatBounds.left,
- lat: lonLatBounds.bottom
- });
- var rightTopPx = this.getOverviewPxFromLonLat({
- lon: lonLatBounds.right,
- lat: lonLatBounds.top
- });
- var bounds = null;
- if (leftBottomPx && rightTopPx) {
- bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
- rightTopPx.x, rightTopPx.y);
- }
- return bounds;
- },
- /**
- * Method: getMapBoundsFromRectBounds
- * Get the map bounds from the rect bounds.
- *
- * Parameters:
- * pxBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
- * translated into lon/lat bounds for the overview map
- */
- getMapBoundsFromRectBounds: function(pxBounds) {
- var leftBottomLonLat = this.getLonLatFromOverviewPx({
- x: pxBounds.left,
- y: pxBounds.bottom
- });
- var rightTopLonLat = this.getLonLatFromOverviewPx({
- x: pxBounds.right,
- y: pxBounds.top
- });
- return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
- rightTopLonLat.lon, rightTopLonLat.lat);
- },
- /**
- * Method: getLonLatFromOverviewPx
- * Get a map location from a pixel location
- *
- * Parameters:
- * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or
- * an object with a
- * 'x' and 'y' properties.
- *
- * Returns:
- * {Object} Location which is the passed-in overview map
- * OpenLayers.Pixel, translated into lon/lat by the overview
- * map. An object with a 'lon' and 'lat' properties.
- */
- getLonLatFromOverviewPx: function(overviewMapPx) {
- var size = this.ovmap.size;
- var res = this.ovmap.getResolution();
- var center = this.ovmap.getExtent().getCenterLonLat();
-
- var deltaX = overviewMapPx.x - (size.w / 2);
- var deltaY = overviewMapPx.y - (size.h / 2);
- return {
- lon: center.lon + deltaX * res,
- lat: center.lat - deltaY * res
- };
- },
- /**
- * Method: getOverviewPxFromLonLat
- * Get a pixel location from a map location
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
- * object with a 'lon' and 'lat' properties.
- *
- * Returns:
- * {Object} Location which is the passed-in OpenLayers.LonLat,
- * translated into overview map pixels
- */
- getOverviewPxFromLonLat: function(lonlat) {
- var res = this.ovmap.getResolution();
- var extent = this.ovmap.getExtent();
- if (extent) {
- return {
- x: Math.round(1/res * (lonlat.lon - extent.left)),
- y: Math.round(1/res * (extent.top - lonlat.lat))
- };
- }
- },
- CLASS_NAME: 'OpenLayers.Control.OverviewMap'
- });
- /* ======================================================================
- OpenLayers/Animation.js
- ====================================================================== */
- /**
- * Copyright (c) 2006-2012 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/SingleFile.js
- */
- /**
- * Namespace: OpenLayers.Animation
- * A collection of utility functions for executing methods that repaint a
- * portion of the browser window. These methods take advantage of the
- * browser's scheduled repaints where requestAnimationFrame is available.
- */
- OpenLayers.Animation = (function(window) {
-
- /**
- * Property: isNative
- * {Boolean} true if a native requestAnimationFrame function is available
- */
- var isNative = !!(window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame);
-
- /**
- * Function: requestFrame
- * Schedule a function to be called at the next available animation frame.
- * Uses the native method where available. Where requestAnimationFrame is
- * not available, setTimeout will be called with a 16ms delay.
- *
- * Parameters:
- * callback - {Function} The function to be called at the next animation frame.
- * element - {DOMElement} Optional element that visually bounds the animation.
- */
- var requestFrame = (function() {
- var request = window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(callback, element) {
- window.setTimeout(callback, 16);
- };
- // bind to window to avoid illegal invocation of native function
- return function(callback, element) {
- request.apply(window, [callback, element]);
- };
- })();
-
- // private variables for animation loops
- var counter = 0;
- var loops = {};
-
- /**
- * Function: start
- * Executes a method with <requestFrame> in series for some
- * duration.
- *
- * Parameters:
- * callback - {Function} The function to be called at the next animation frame.
- * duration - {Number} Optional duration for the loop. If not provided, the
- * animation loop will execute indefinitely.
- * element - {DOMElement} Optional element that visually bounds the animation.
- *
- * Returns:
- * {Number} Identifier for the animation loop. Used to stop animations with
- * <stop>.
- */
- function start(callback, duration, element) {
- duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;
- var id = ++counter;
- var start = +new Date;
- loops[id] = function() {
- if (loops[id] && +new Date - start <= duration) {
- callback();
- if (loops[id]) {
- requestFrame(loops[id], element);
- }
- } else {
- delete loops[id];
- }
- };
- requestFrame(loops[id], element);
- return id;
- }
-
- /**
- * Function: stop
- * Terminates an animation loop started with <start>.
- *
- * Parameters:
- * id - {Number} Identifier returned from <start>.
- */
- function stop(id) {
- delete loops[id];
- }
-
- return {
- isNative: isNative,
- requestFrame: requestFrame,
- start: start,
- stop: stop
- };
-
- })(window);
- /* ======================================================================
- OpenLayers/Tween.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Animation.js
- */
- /**
- * Namespace: OpenLayers.Tween
- */
- OpenLayers.Tween = OpenLayers.Class({
-
- /**
- * APIProperty: easing
- * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
- * Defaultly set to OpenLayers.Easing.Expo.easeOut
- */
- easing: null,
-
- /**
- * APIProperty: begin
- * {Object} Values to start the animation with
- */
- begin: null,
-
- /**
- * APIProperty: finish
- * {Object} Values to finish the animation with
- */
- finish: null,
-
- /**
- * APIProperty: duration
- * {int} duration of the tween (number of steps)
- */
- duration: null,
-
- /**
- * APIProperty: callbacks
- * {Object} An object with start, eachStep and done properties whose values
- * are functions to be call during the animation. They are passed the
- * current computed value as argument.
- */
- callbacks: null,
-
- /**
- * Property: time
- * {int} Step counter
- */
- time: null,
-
- /**
- * Property: animationId
- * {int} Loop id returned by OpenLayers.Animation.start
- */
- animationId: null,
-
- /**
- * Property: playing
- * {Boolean} Tells if the easing is currently playing
- */
- playing: false,
-
- /**
- * Constructor: OpenLayers.Tween
- * Creates a Tween.
- *
- * Parameters:
- * easing - {<OpenLayers.Easing>(Function)} easing function method to use
- */
- initialize: function(easing) {
- this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
- },
-
- /**
- * APIMethod: start
- * Plays the Tween, and calls the callback method on each step
- *
- * Parameters:
- * begin - {Object} values to start the animation with
- * finish - {Object} values to finish the animation with
- * duration - {int} duration of the tween (number of steps)
- * options - {Object} hash of options (for example callbacks (start, eachStep, done))
- */
- start: function(begin, finish, duration, options) {
- this.playing = true;
- this.begin = begin;
- this.finish = finish;
- this.duration = duration;
- this.callbacks = options.callbacks;
- this.time = 0;
- OpenLayers.Animation.stop(this.animationId);
- this.animationId = null;
- if (this.callbacks && this.callbacks.start) {
- this.callbacks.start.call(this, this.begin);
- }
- this.animationId = OpenLayers.Animation.start(
- OpenLayers.Function.bind(this.play, this)
- );
- },
-
- /**
- * APIMethod: stop
- * Stops the Tween, and calls the done callback
- * Doesn't do anything if animation is already finished
- */
- stop: function() {
- if (!this.playing) {
- return;
- }
-
- if (this.callbacks && this.callbacks.done) {
- this.callbacks.done.call(this, this.finish);
- }
- OpenLayers.Animation.stop(this.animationId);
- this.animationId = null;
- this.playing = false;
- },
-
- /**
- * Method: play
- * Calls the appropriate easing method
- */
- play: function() {
- var value = {};
- for (var i in this.begin) {
- var b = this.begin[i];
- var f = this.finish[i];
- if (b == null || f == null || isNaN(b) || isNaN(f)) {
- throw new TypeError('invalid value for Tween');
- }
- var c = f - b;
- value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
- }
- this.time++;
-
- if (this.callbacks && this.callbacks.eachStep) {
- this.callbacks.eachStep.call(this, value);
- }
-
- if (this.time > this.duration) {
- this.stop();
- }
- },
-
- /**
- * Create empty functions for all easing methods.
- */
- CLASS_NAME: "OpenLayers.Tween"
- });
- /**
- * Namespace: OpenLayers.Easing
- *
- * Credits:
- * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
- */
- OpenLayers.Easing = {
- /**
- * Create empty functions for all easing methods.
- */
- CLASS_NAME: "OpenLayers.Easing"
- };
- /**
- * Namespace: OpenLayers.Easing.Linear
- */
- OpenLayers.Easing.Linear = {
-
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeIn: function(t, b, c, d) {
- return c*t/d + b;
- },
-
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeOut: function(t, b, c, d) {
- return c*t/d + b;
- },
-
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeInOut: function(t, b, c, d) {
- return c*t/d + b;
- },
- CLASS_NAME: "OpenLayers.Easing.Linear"
- };
- /**
- * Namespace: OpenLayers.Easing.Expo
- */
- OpenLayers.Easing.Expo = {
-
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeIn: function(t, b, c, d) {
- return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
- },
-
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeOut: function(t, b, c, d) {
- return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
- },
-
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeInOut: function(t, b, c, d) {
- if (t==0) return b;
- if (t==d) return b+c;
- if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
- return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
- },
- CLASS_NAME: "OpenLayers.Easing.Expo"
- };
- /**
- * Namespace: OpenLayers.Easing.Quad
- */
- OpenLayers.Easing.Quad = {
-
- /**
- * Function: easeIn
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeIn: function(t, b, c, d) {
- return c*(t/=d)*t + b;
- },
-
- /**
- * Function: easeOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeOut: function(t, b, c, d) {
- return -c *(t/=d)*(t-2) + b;
- },
-
- /**
- * Function: easeInOut
- *
- * Parameters:
- * t - {Float} time
- * b - {Float} beginning position
- * c - {Float} total change
- * d - {Float} duration of the transition
- *
- * Returns:
- * {Float}
- */
- easeInOut: function(t, b, c, d) {
- if ((t/=d/2) < 1) return c/2*t*t + b;
- return -c/2 * ((--t)*(t-2) - 1) + b;
- },
- CLASS_NAME: "OpenLayers.Easing.Quad"
- };
- /* ======================================================================
- OpenLayers/Projection.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Util.js
- */
- /**
- * Namespace: OpenLayers.Projection
- * Methods for coordinate transforms between coordinate systems. By default,
- * OpenLayers ships with the ability to transform coordinates between
- * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)
- * coordinate reference systems. See the <transform> method for details
- * on usage.
- *
- * Additional transforms may be added by using the <proj4js at http://proj4js.org/>
- * library. If the proj4js library is included, the <transform> method
- * will work between any two coordinate reference systems with proj4js
- * definitions.
- *
- * If the proj4js library is not included, or if you wish to allow transforms
- * between arbitrary coordinate reference systems, use the <addTransform>
- * method to register a custom transform method.
- */
- OpenLayers.Projection = OpenLayers.Class({
- /**
- * Property: proj
- * {Object} Proj4js.Proj instance.
- */
- proj: null,
-
- /**
- * Property: projCode
- * {String}
- */
- projCode: null,
-
- /**
- * Property: titleRegEx
- * {RegExp} regular expression to strip the title from a proj4js definition
- */
- titleRegEx: /\+title=[^\+]*/,
- /**
- * Constructor: OpenLayers.Projection
- * This class offers several methods for interacting with a wrapped
- * pro4js projection object.
- *
- * Parameters:
- * projCode - {String} A string identifying the Well Known Identifier for
- * the projection.
- * options - {Object} An optional object to set additional properties
- * on the projection.
- *
- * Returns:
- * {<OpenLayers.Projection>} A projection object.
- */
- initialize: function(projCode, options) {
- OpenLayers.Util.extend(this, options);
- this.projCode = projCode;
- if (window.Proj4js) {
- this.proj = new Proj4js.Proj(projCode);
- }
- },
-
- /**
- * APIMethod: getCode
- * Get the string SRS code.
- *
- * Returns:
- * {String} The SRS code.
- */
- getCode: function() {
- return this.proj ? this.proj.srsCode : this.projCode;
- },
-
- /**
- * APIMethod: getUnits
- * Get the units string for the projection -- returns null if
- * proj4js is not available.
- *
- * Returns:
- * {String} The units abbreviation.
- */
- getUnits: function() {
- return this.proj ? this.proj.units : null;
- },
- /**
- * Method: toString
- * Convert projection to string (getCode wrapper).
- *
- * Returns:
- * {String} The projection code.
- */
- toString: function() {
- return this.getCode();
- },
- /**
- * Method: equals
- * Test equality of two projection instances. Determines equality based
- * soley on the projection code.
- *
- * Returns:
- * {Boolean} The two projections are equivalent.
- */
- equals: function(projection) {
- var p = projection, equals = false;
- if (p) {
- if (!(p instanceof OpenLayers.Projection)) {
- p = new OpenLayers.Projection(p);
- }
- if (window.Proj4js && this.proj.defData && p.proj.defData) {
- equals = this.proj.defData.replace(this.titleRegEx, "") ==
- p.proj.defData.replace(this.titleRegEx, "");
- } else if (p.getCode) {
- var source = this.getCode(), target = p.getCode();
- equals = source == target ||
- !!OpenLayers.Projection.transforms[source] &&
- OpenLayers.Projection.transforms[source][target] ===
- OpenLayers.Projection.nullTransform;
- }
- }
- return equals;
- },
- /* Method: destroy
- * Destroy projection object.
- */
- destroy: function() {
- delete this.proj;
- delete this.projCode;
- },
-
- CLASS_NAME: "OpenLayers.Projection"
- });
- /**
- * Property: transforms
- * {Object} Transforms is an object, with from properties, each of which may
- * have a to property. This allows you to define projections without
- * requiring support for proj4js to be included.
- *
- * This object has keys which correspond to a 'source' projection object. The
- * keys should be strings, corresponding to the projection.getCode() value.
- * Each source projection object should have a set of destination projection
- * keys included in the object.
- *
- * Each value in the destination object should be a transformation function,
- * where the function is expected to be passed an object with a .x and a .y
- * property. The function should return the object, with the .x and .y
- * transformed according to the transformation function.
- *
- * Note - Properties on this object should not be set directly. To add a
- * transform method to this object, use the <addTransform> method. For an
- * example of usage, see the OpenLayers.Layer.SphericalMercator file.
- */
- OpenLayers.Projection.transforms = {};
- /**
- * APIProperty: defaults
- * {Object} Defaults for the SRS codes known to OpenLayers (currently
- * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,
- * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,
- * maxExtent (the validity extent for the SRS) and yx (true if this SRS is
- * known to have a reverse axis order).
- */
- OpenLayers.Projection.defaults = {
- "EPSG:4326": {
- units: "degrees",
- maxExtent: [-180, -90, 180, 90],
- yx: true
- },
- "CRS:84": {
- units: "degrees",
- maxExtent: [-180, -90, 180, 90]
- },
- "EPSG:900913": {
- units: "m",
- maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
- }
- };
- /**
- * APIMethod: addTransform
- * Set a custom transform method between two projections. Use this method in
- * cases where the proj4js lib is not available or where custom projections
- * need to be handled.
- *
- * Parameters:
- * from - {String} The code for the source projection
- * to - {String} the code for the destination projection
- * method - {Function} A function that takes a point as an argument and
- * transforms that point from the source to the destination projection
- * in place. The original point should be modified.
- */
- OpenLayers.Projection.addTransform = function(from, to, method) {
- if (method === OpenLayers.Projection.nullTransform) {
- var defaults = OpenLayers.Projection.defaults[from];
- if (defaults && !OpenLayers.Projection.defaults[to]) {
- OpenLayers.Projection.defaults[to] = defaults;
- }
- }
- if(!OpenLayers.Projection.transforms[from]) {
- OpenLayers.Projection.transforms[from] = {};
- }
- OpenLayers.Projection.transforms[from][to] = method;
- };
- /**
- * APIMethod: transform
- * Transform a point coordinate from one projection to another. Note that
- * the input point is transformed in place.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point> | Object} An object with x and y
- * properties representing coordinates in those dimensions.
- * source - {OpenLayers.Projection} Source map coordinate system
- * dest - {OpenLayers.Projection} Destination map coordinate system
- *
- * Returns:
- * point - {object} A transformed coordinate. The original point is modified.
- */
- OpenLayers.Projection.transform = function(point, source, dest) {
- if (source && dest) {
- if (!(source instanceof OpenLayers.Projection)) {
- source = new OpenLayers.Projection(source);
- }
- if (!(dest instanceof OpenLayers.Projection)) {
- dest = new OpenLayers.Projection(dest);
- }
- if (source.proj && dest.proj) {
- point = Proj4js.transform(source.proj, dest.proj, point);
- } else {
- var sourceCode = source.getCode();
- var destCode = dest.getCode();
- var transforms = OpenLayers.Projection.transforms;
- if (transforms[sourceCode] && transforms[sourceCode][destCode]) {
- transforms[sourceCode][destCode](point);
- }
- }
- }
- return point;
- };
- /**
- * APIFunction: nullTransform
- * A null transformation - useful for defining projection aliases when
- * proj4js is not available:
- *
- * (code)
- * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913",
- * OpenLayers.Projection.nullTransform);
- * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857",
- * OpenLayers.Projection.nullTransform);
- * (end)
- */
- OpenLayers.Projection.nullTransform = function(point) {
- return point;
- };
- /**
- * Note: Transforms for web mercator <-> geographic
- * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
- * OpenLayers originally started referring to EPSG:900913 as web mercator.
- * The EPSG has declared EPSG:3857 to be web mercator.
- * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
- * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084.
- * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and
- * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis
- * order for EPSG:4326.
- */
- (function() {
- var pole = 20037508.34;
- function inverseMercator(xy) {
- xy.x = 180 * xy.x / pole;
- xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);
- return xy;
- }
- function forwardMercator(xy) {
- xy.x = xy.x * pole / 180;
- xy.y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;
- return xy;
- }
- function map(base, codes) {
- var add = OpenLayers.Projection.addTransform;
- var same = OpenLayers.Projection.nullTransform;
- var i, len, code, other, j;
- for (i=0, len=codes.length; i<len; ++i) {
- code = codes[i];
- add(base, code, forwardMercator);
- add(code, base, inverseMercator);
- for (j=i+1; j<len; ++j) {
- other = codes[j];
- add(code, other, same);
- add(other, code, same);
- }
- }
- }
-
- // list of equivalent codes for web mercator
- var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"],
- geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"],
- i;
- for (i=mercator.length-1; i>=0; --i) {
- map(mercator[i], geographic);
- }
- for (i=geographic.length-1; i>=0; --i) {
- map(geographic[i], mercator);
- }
- })();
- /* ======================================================================
- OpenLayers/Map.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Events.js
- * @requires OpenLayers/Tween.js
- * @requires OpenLayers/Projection.js
- */
- /**
- * Class: OpenLayers.Map
- * Instances of OpenLayers.Map are interactive maps embedded in a web page.
- * Create a new map with the <OpenLayers.Map> constructor.
- *
- * On their own maps do not provide much functionality. To extend a map
- * it's necessary to add controls (<OpenLayers.Control>) and
- * layers (<OpenLayers.Layer>) to the map.
- */
- OpenLayers.Map = OpenLayers.Class({
-
- /**
- * Constant: Z_INDEX_BASE
- * {Object} Base z-indexes for different classes of thing
- */
- Z_INDEX_BASE: {
- BaseLayer: 100,
- Overlay: 325,
- Feature: 725,
- Popup: 750,
- Control: 1000
- },
- /**
- * APIProperty: events
- * {<OpenLayers.Events>}
- *
- * Register a listener for a particular event with the following syntax:
- * (code)
- * map.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * All event objects have at least the following properties:
- * object - {Object} A reference to map.events.object.
- * element - {DOMElement} A reference to map.events.element.
- *
- * Browser events have the following additional properties:
- * xy - {<OpenLayers.Pixel>} The pixel location of the event (relative
- * to the the map viewport).
- *
- * Supported map event types:
- * preaddlayer - triggered before a layer has been added. The event
- * object will include a *layer* property that references the layer
- * to be added. When a listener returns "false" the adding will be
- * aborted.
- * addlayer - triggered after a layer has been added. The event object
- * will include a *layer* property that references the added layer.
- * preremovelayer - triggered before a layer has been removed. The event
- * object will include a *layer* property that references the layer
- * to be removed. When a listener returns "false" the removal will be
- * aborted.
- * removelayer - triggered after a layer has been removed. The event
- * object will include a *layer* property that references the removed
- * layer.
- * changelayer - triggered after a layer name change, order change,
- * opacity change, params change, visibility change (due to resolution
- * thresholds) or attribution change (due to extent change). Listeners
- * will receive an event object with *layer* and *property* properties.
- * The *layer* property will be a reference to the changed layer. The
- * *property* property will be a key to the changed property (name,
- * order, opacity, params, visibility or attribution).
- * movestart - triggered after the start of a drag, pan, or zoom
- * move - triggered after each drag, pan, or zoom
- * moveend - triggered after a drag, pan, or zoom completes
- * zoomend - triggered after a zoom completes
- * mouseover - triggered after mouseover the map
- * mouseout - triggered after mouseout the map
- * mousemove - triggered after mousemove the map
- * changebaselayer - triggered after the base layer changes
- */
- /**
- * Property: id
- * {String} Unique identifier for the map
- */
- id: null,
-
- /**
- * Property: fractionalZoom
- * {Boolean} For a base layer that supports it, allow the map resolution
- * to be set to a value between one of the values in the resolutions
- * array. Default is false.
- *
- * When fractionalZoom is set to true, it is possible to zoom to
- * an arbitrary extent. This requires a base layer from a source
- * that supports requests for arbitrary extents (i.e. not cached
- * tiles on a regular lattice). This means that fractionalZoom
- * will not work with commercial layers (Google, Yahoo, VE), layers
- * using TileCache, or any other pre-cached data sources.
- *
- * If you are using fractionalZoom, then you should also use
- * <getResolutionForZoom> instead of layer.resolutions[zoom] as the
- * former works for non-integer zoom levels.
- */
- fractionalZoom: false,
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the map
- */
- events: null,
-
- /**
- * APIProperty: allOverlays
- * {Boolean} Allow the map to function with "overlays" only. Defaults to
- * false. If true, the lowest layer in the draw order will act as
- * the base layer. In addition, if set to true, all layers will
- * have isBaseLayer set to false when they are added to the map.
- *
- * Note:
- * If you set map.allOverlays to true, then you *cannot* use
- * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,
- * the lowest layer in the draw layer is the base layer. So, to change
- * the base layer, use <setLayerIndex> or <raiseLayer> to set the layer
- * index to 0.
- */
- allOverlays: false,
- /**
- * APIProperty: div
- * {DOMElement|String} The element that contains the map (or an id for
- * that element). If the <OpenLayers.Map> constructor is called
- * with two arguments, this should be provided as the first argument.
- * Alternatively, the map constructor can be called with the options
- * object as the only argument. In this case (one argument), a
- * div property may or may not be provided. If the div property
- * is not provided, the map can be rendered to a container later
- * using the <render> method.
- *
- * Note:
- * If you are calling <render> after map construction, do not use
- * <maxResolution> auto. Instead, divide your <maxExtent> by your
- * maximum expected dimension.
- */
- div: null,
-
- /**
- * Property: dragging
- * {Boolean} The map is currently being dragged.
- */
- dragging: false,
- /**
- * Property: size
- * {<OpenLayers.Size>} Size of the main div (this.div)
- */
- size: null,
-
- /**
- * Property: viewPortDiv
- * {HTMLDivElement} The element that represents the map viewport
- */
- viewPortDiv: null,
- /**
- * Property: layerContainerOrigin
- * {<OpenLayers.LonLat>} The lonlat at which the later container was
- * re-initialized (on-zoom)
- */
- layerContainerOrigin: null,
- /**
- * Property: layerContainerDiv
- * {HTMLDivElement} The element that contains the layers.
- */
- layerContainerDiv: null,
- /**
- * APIProperty: layers
- * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
- */
- layers: null,
- /**
- * APIProperty: controls
- * {Array(<OpenLayers.Control>)} List of controls associated with the map.
- *
- * If not provided in the map options at construction, the map will
- * by default be given the following controls if present in the build:
- * - <OpenLayers.Control.Navigation> or <OpenLayers.Control.TouchNavigation>
- * - <OpenLayers.Control.Zoom> or <OpenLayers.Control.PanZoom>
- * - <OpenLayers.Control.ArgParser>
- * - <OpenLayers.Control.Attribution>
- */
- controls: null,
- /**
- * Property: popups
- * {Array(<OpenLayers.Popup>)} List of popups associated with the map
- */
- popups: null,
- /**
- * APIProperty: baseLayer
- * {<OpenLayers.Layer>} The currently selected base layer. This determines
- * min/max zoom level, projection, etc.
- */
- baseLayer: null,
-
- /**
- * Property: center
- * {<OpenLayers.LonLat>} The current center of the map
- */
- center: null,
- /**
- * Property: resolution
- * {Float} The resolution of the map.
- */
- resolution: null,
- /**
- * Property: zoom
- * {Integer} The current zoom level of the map
- */
- zoom: 0,
- /**
- * Property: panRatio
- * {Float} The ratio of the current extent within
- * which panning will tween.
- */
- panRatio: 1.5,
- /**
- * APIProperty: options
- * {Object} The options object passed to the class constructor. Read-only.
- */
- options: null,
- // Options
- /**
- * APIProperty: tileSize
- * {<OpenLayers.Size>} Set in the map options to override the default tile
- * size for this map.
- */
- tileSize: null,
- /**
- * APIProperty: projection
- * {String} Set in the map options to specify the default projection
- * for layers added to this map. When using a projection other than EPSG:4326
- * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),
- * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326".
- * Note that the projection of the map is usually determined
- * by that of the current baseLayer (see <baseLayer> and <getProjectionObject>).
- */
- projection: "EPSG:4326",
-
- /**
- * APIProperty: units
- * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm',
- * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.
- * Only required if both map and layers do not define a projection,
- * or if they define a projection which does not define units
- */
- units: null,
- /**
- * APIProperty: resolutions
- * {Array(Float)} A list of map resolutions (map units per pixel) in
- * descending order. If this is not set in the layer constructor, it
- * will be set based on other resolution related properties
- * (maxExtent, maxResolution, maxScale, etc.).
- */
- resolutions: null,
- /**
- * APIProperty: maxResolution
- * {Float} Required if you are not displaying the whole world on a tile
- * with the size specified in <tileSize>.
- */
- maxResolution: null,
- /**
- * APIProperty: minResolution
- * {Float}
- */
- minResolution: null,
- /**
- * APIProperty: maxScale
- * {Float}
- */
- maxScale: null,
- /**
- * APIProperty: minScale
- * {Float}
- */
- minScale: null,
- /**
- * APIProperty: maxExtent
- * {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * The maximum extent for the map. Defaults to the
- * whole world in decimal degrees (-180, -90, 180, 90). Specify a
- * different extent in the map options if you are not using a geographic
- * projection and displaying the whole world. To restrict user panning
- * and zooming of the map, use <restrictedExtent> instead. The value
- * for <maxExtent> will change calculations for tile URLs.
- */
- maxExtent: null,
-
- /**
- * APIProperty: minExtent
- * {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * The minimum extent for the map. Defaults to null.
- */
- minExtent: null,
-
- /**
- * APIProperty: restrictedExtent
- * {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * Limit map navigation to this extent where possible.
- * If a non-null restrictedExtent is set, panning will be restricted
- * to the given bounds. In addition, zooming to a resolution that
- * displays more than the restricted extent will center the map
- * on the restricted extent. If you wish to limit the zoom level
- * or resolution, use maxResolution.
- */
- restrictedExtent: null,
- /**
- * APIProperty: numZoomLevels
- * {Integer} Number of zoom levels for the map. Defaults to 16. Set a
- * different value in the map options if needed.
- */
- numZoomLevels: 16,
- /**
- * APIProperty: theme
- * {String} Relative path to a CSS file from which to load theme styles.
- * Specify null in the map options (e.g. {theme: null}) if you
- * want to get cascading style declarations - by putting links to
- * stylesheets or style declarations directly in your page.
- */
- theme: null,
-
- /**
- * APIProperty: displayProjection
- * {<OpenLayers.Projection>} Requires proj4js support for projections other
- * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by
- * several controls to display data to user. If this property is set,
- * it will be set on any control which has a null displayProjection
- * property at the time the control is added to the map.
- */
- displayProjection: null,
- /**
- * APIProperty: fallThrough
- * {Boolean} Should OpenLayers allow events on the map to fall through to
- * other elements on the page, or should it swallow them? (#457)
- * Default is to fall through.
- */
- fallThrough: true,
-
- /**
- * Property: panTween
- * {<OpenLayers.Tween>} Animated panning tween object, see panTo()
- */
- panTween: null,
- /**
- * APIProperty: eventListeners
- * {Object} If set as an option at construction, the eventListeners
- * object will be registered with <OpenLayers.Events.on>. Object
- * structure must be a listeners object as shown in the example for
- * the events.on method.
- */
- eventListeners: null,
- /**
- * APIProperty: panMethod
- * {Function} The Easing function to be used for tweening. Default is
- * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off
- * animated panning.
- */
- panMethod: OpenLayers.Easing.Expo.easeOut,
-
- /**
- * Property: panDuration
- * {Integer} The number of steps to be passed to the
- * OpenLayers.Tween.start() method when the map is
- * panned.
- * Default is 50.
- */
- panDuration: 50,
-
- /**
- * Property: paddingForPopups
- * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent
- * the popup from getting too close to the map border.
- */
- paddingForPopups : null,
-
- /**
- * Property: minPx
- * {Object} An object with a 'x' and 'y' values that is the lower
- * left of maxExtent in viewport pixel space.
- * Used to verify in moveByPx that the new location we're moving to
- * is valid. It is also used in the getLonLatFromViewPortPx function
- * of Layer.
- */
- minPx: null,
-
- /**
- * Property: maxPx
- * {Object} An object with a 'x' and 'y' values that is the top
- * right of maxExtent in viewport pixel space.
- * Used to verify in moveByPx that the new location we're moving to
- * is valid.
- */
- maxPx: null,
-
- /**
- * Constructor: OpenLayers.Map
- * Constructor for a new OpenLayers.Map instance. There are two possible
- * ways to call the map constructor. See the examples below.
- *
- * Parameters:
- * div - {DOMElement|String} The element or id of an element in your page
- * that will contain the map. May be omitted if the <div> option is
- * provided or if you intend to call the <render> method later.
- * options - {Object} Optional object with properties to tag onto the map.
- *
- * Valid options (in addition to the listed API properties):
- * center - {<OpenLayers.LonLat>|Array} The default initial center of the map.
- * If provided as array, the first value is the x coordinate,
- * and the 2nd value is the y coordinate.
- * Only specify if <layers> is provided.
- * Note that if an ArgParser/Permalink control is present,
- * and the querystring contains coordinates, center will be set
- * by that, and this option will be ignored.
- * zoom - {Number} The initial zoom level for the map. Only specify if
- * <layers> is provided.
- * Note that if an ArgParser/Permalink control is present,
- * and the querystring contains a zoom level, zoom will be set
- * by that, and this option will be ignored.
- * extent - {<OpenLayers.Bounds>|Array} The initial extent of the map.
- * If provided as an array, the array should consist of
- * four values (left, bottom, right, top).
- * Only specify if <center> and <zoom> are not provided.
- *
- * Examples:
- * (code)
- * // create a map with default options in an element with the id "map1"
- * var map = new OpenLayers.Map("map1");
- *
- * // create a map with non-default options in an element with id "map2"
- * var options = {
- * projection: "EPSG:3857",
- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
- * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)
- * };
- * var map = new OpenLayers.Map("map2", options);
- *
- * // map with non-default options - same as above but with a single argument,
- * // a restricted extent, and using arrays for bounds and center
- * var map = new OpenLayers.Map({
- * div: "map_id",
- * projection: "EPSG:3857",
- * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],
- * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],
- * center: [-12356463.476333, 5621521.4854095]
- * });
- *
- * // create a map without a reference to a container - call render later
- * var map = new OpenLayers.Map({
- * projection: "EPSG:3857",
- * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000)
- * });
- * (end)
- */
- initialize: function (div, options) {
-
- // If only one argument is provided, check if it is an object.
- if(arguments.length === 1 && typeof div === "object") {
- options = div;
- div = options && options.div;
- }
- // Simple-type defaults are set in class definition.
- // Now set complex-type defaults
- this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
- OpenLayers.Map.TILE_HEIGHT);
-
- this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
- this.theme = OpenLayers._getScriptLocation() +
- 'theme/default/style.css';
- // backup original options
- this.options = OpenLayers.Util.extend({}, options);
- // now override default options
- OpenLayers.Util.extend(this, options);
-
- var projCode = this.projection instanceof OpenLayers.Projection ?
- this.projection.projCode : this.projection;
- OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);
-
- // allow extents and center to be arrays
- if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {
- this.maxExtent = new OpenLayers.Bounds(this.maxExtent);
- }
- if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) {
- this.minExtent = new OpenLayers.Bounds(this.minExtent);
- }
- if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) {
- this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent);
- }
- if (this.center && !(this.center instanceof OpenLayers.LonLat)) {
- this.center = new OpenLayers.LonLat(this.center);
- }
- // initialize layers array
- this.layers = [];
- this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
- this.div = OpenLayers.Util.getElement(div);
- if(!this.div) {
- this.div = document.createElement("div");
- this.div.style.height = "1px";
- this.div.style.width = "1px";
- }
-
- OpenLayers.Element.addClass(this.div, 'olMap');
- // the viewPortDiv is the outermost div we modify
- var id = this.id + "_OpenLayers_ViewPort";
- this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
- "relative", null,
- "hidden");
- this.viewPortDiv.style.width = "100%";
- this.viewPortDiv.style.height = "100%";
- this.viewPortDiv.className = "olMapViewport";
- this.div.appendChild(this.viewPortDiv);
- this.events = new OpenLayers.Events(
- this, this.viewPortDiv, null, this.fallThrough,
- {includeXY: true}
- );
- // the layerContainerDiv is the one that holds all the layers
- id = this.id + "_OpenLayers_Container";
- this.layerContainerDiv = OpenLayers.Util.createDiv(id);
- this.layerContainerDiv.style.width = '100px';
- this.layerContainerDiv.style.height = '100px';
- this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
-
- this.viewPortDiv.appendChild(this.layerContainerDiv);
- this.updateSize();
- if(this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
- }
-
- // Because Mozilla does not support the "resize" event for elements
- // other than "window", we need to put a hack here.
- if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) {
- // If IE < 9, register the resize on the div
- this.events.register("resize", this, this.updateSize);
- } else {
- // Else updateSize on catching the window's resize
- // Note that this is ok, as updateSize() does nothing if the
- // map's size has not actually changed.
- this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,
- this);
- OpenLayers.Event.observe(window, 'resize',
- this.updateSizeDestroy);
- }
-
- // only append link stylesheet if the theme property is set
- if(this.theme) {
- // check existing links for equivalent url
- var addNode = true;
- var nodes = document.getElementsByTagName('link');
- for(var i=0, len=nodes.length; i<len; ++i) {
- if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
- this.theme)) {
- addNode = false;
- break;
- }
- }
- // only add a new node if one with an equivalent url hasn't already
- // been added
- if(addNode) {
- var cssNode = document.createElement('link');
- cssNode.setAttribute('rel', 'stylesheet');
- cssNode.setAttribute('type', 'text/css');
- cssNode.setAttribute('href', this.theme);
- document.getElementsByTagName('head')[0].appendChild(cssNode);
- }
- }
-
- if (this.controls == null) { // default controls
- this.controls = [];
- if (OpenLayers.Control != null) { // running full or lite?
- // Navigation or TouchNavigation depending on what is in build
- if (OpenLayers.Control.Navigation) {
- this.controls.push(new OpenLayers.Control.Navigation());
- } else if (OpenLayers.Control.TouchNavigation) {
- this.controls.push(new OpenLayers.Control.TouchNavigation());
- }
- if (OpenLayers.Control.Zoom) {
- this.controls.push(new OpenLayers.Control.Zoom());
- } else if (OpenLayers.Control.PanZoom) {
- this.controls.push(new OpenLayers.Control.PanZoom());
- }
- if (OpenLayers.Control.ArgParser) {
- this.controls.push(new OpenLayers.Control.ArgParser());
- }
- if (OpenLayers.Control.Attribution) {
- this.controls.push(new OpenLayers.Control.Attribution());
- }
- }
- }
- for(var i=0, len=this.controls.length; i<len; i++) {
- this.addControlToMap(this.controls[i]);
- }
- this.popups = [];
- this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
-
- // always call map.destroy()
- OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
-
- // add any initial layers
- if (options && options.layers) {
- /**
- * If you have set options.center, the map center property will be
- * set at this point. However, since setCenter has not been called,
- * addLayers gets confused. So we delete the map center in this
- * case. Because the check below uses options.center, it will
- * be properly set below.
- */
- delete this.center;
- this.addLayers(options.layers);
- // set center (and optionally zoom)
- if (options.center && !this.getCenter()) {
- // zoom can be undefined here
- this.setCenter(options.center, options.zoom);
- }
- }
- },
- /**
- * APIMethod: getViewport
- * Get the DOMElement representing the view port.
- *
- * Returns:
- * {DOMElement}
- */
- getViewport: function() {
- return this.viewPortDiv;
- },
-
- /**
- * APIMethod: render
- * Render the map to a specified container.
- *
- * Parameters:
- * div - {String|DOMElement} The container that the map should be rendered
- * to. If different than the current container, the map viewport
- * will be moved from the current to the new container.
- */
- render: function(div) {
- this.div = OpenLayers.Util.getElement(div);
- OpenLayers.Element.addClass(this.div, 'olMap');
- this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
- this.div.appendChild(this.viewPortDiv);
- this.updateSize();
- },
- /**
- * Method: unloadDestroy
- * Function that is called to destroy the map on page unload. stored here
- * so that if map is manually destroyed, we can unregister this.
- */
- unloadDestroy: null,
-
- /**
- * Method: updateSizeDestroy
- * When the map is destroyed, we need to stop listening to updateSize
- * events: this method stores the function we need to unregister in
- * non-IE browsers.
- */
- updateSizeDestroy: null,
- /**
- * APIMethod: destroy
- * Destroy this map.
- * Note that if you are using an application which removes a container
- * of the map from the DOM, you need to ensure that you destroy the
- * map *before* this happens; otherwise, the page unload handler
- * will fail because the DOM elements that map.destroy() wants
- * to clean up will be gone. (See
- * http://trac.osgeo.org/openlayers/ticket/2277 for more information).
- * This will apply to GeoExt and also to other applications which
- * modify the DOM of the container of the OpenLayers Map.
- */
- destroy:function() {
- // if unloadDestroy is null, we've already been destroyed
- if (!this.unloadDestroy) {
- return false;
- }
-
- // make sure panning doesn't continue after destruction
- if(this.panTween) {
- this.panTween.stop();
- this.panTween = null;
- }
- // map has been destroyed. dont do it again!
- OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
- this.unloadDestroy = null;
- if (this.updateSizeDestroy) {
- OpenLayers.Event.stopObserving(window, 'resize',
- this.updateSizeDestroy);
- } else {
- this.events.unregister("resize", this, this.updateSize);
- }
-
- this.paddingForPopups = null;
- if (this.controls != null) {
- for (var i = this.controls.length - 1; i>=0; --i) {
- this.controls[i].destroy();
- }
- this.controls = null;
- }
- if (this.layers != null) {
- for (var i = this.layers.length - 1; i>=0; --i) {
- //pass 'false' to destroy so that map wont try to set a new
- // baselayer after each baselayer is removed
- this.layers[i].destroy(false);
- }
- this.layers = null;
- }
- if (this.viewPortDiv) {
- this.div.removeChild(this.viewPortDiv);
- }
- this.viewPortDiv = null;
- if(this.eventListeners) {
- this.events.un(this.eventListeners);
- this.eventListeners = null;
- }
- this.events.destroy();
- this.events = null;
- this.options = null;
- },
- /**
- * APIMethod: setOptions
- * Change the map options
- *
- * Parameters:
- * options - {Object} Hashtable of options to tag to the map
- */
- setOptions: function(options) {
- var updatePxExtent = this.minPx &&
- options.restrictedExtent != this.restrictedExtent;
- OpenLayers.Util.extend(this, options);
- // force recalculation of minPx and maxPx
- updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, {
- forceZoomChange: true
- });
- },
- /**
- * APIMethod: getTileSize
- * Get the tile size for the map
- *
- * Returns:
- * {<OpenLayers.Size>}
- */
- getTileSize: function() {
- return this.tileSize;
- },
- /**
- * APIMethod: getBy
- * Get a list of objects given a property and a match item.
- *
- * Parameters:
- * array - {String} A property on the map whose value is an array.
- * property - {String} A property on each item of the given array.
- * match - {String | Object} A string to match. Can also be a regular
- * expression literal or object. In addition, it can be any object
- * with a method named test. For reqular expressions or other, if
- * match.test(map[array][i][property]) evaluates to true, the item will
- * be included in the array returned. If no items are found, an empty
- * array is returned.
- *
- * Returns:
- * {Array} An array of items where the given property matches the given
- * criteria.
- */
- getBy: function(array, property, match) {
- var test = (typeof match.test == "function");
- var found = OpenLayers.Array.filter(this[array], function(item) {
- return item[property] == match || (test && match.test(item[property]));
- });
- return found;
- },
- /**
- * APIMethod: getLayersBy
- * Get a list of layers with properties matching the given criteria.
- *
- * Parameters:
- * property - {String} A layer property to be matched.
- * match - {String | Object} A string to match. Can also be a regular
- * expression literal or object. In addition, it can be any object
- * with a method named test. For reqular expressions or other, if
- * match.test(layer[property]) evaluates to true, the layer will be
- * included in the array returned. If no layers are found, an empty
- * array is returned.
- *
- * Returns:
- * {Array(<OpenLayers.Layer>)} A list of layers matching the given criteria.
- * An empty array is returned if no matches are found.
- */
- getLayersBy: function(property, match) {
- return this.getBy("layers", property, match);
- },
- /**
- * APIMethod: getLayersByName
- * Get a list of layers with names matching the given name.
- *
- * Parameters:
- * match - {String | Object} A layer name. The name can also be a regular
- * expression literal or object. In addition, it can be any object
- * with a method named test. For reqular expressions or other, if
- * name.test(layer.name) evaluates to true, the layer will be included
- * in the list of layers returned. If no layers are found, an empty
- * array is returned.
- *
- * Returns:
- * {Array(<OpenLayers.Layer>)} A list of layers matching the given name.
- * An empty array is returned if no matches are found.
- */
- getLayersByName: function(match) {
- return this.getLayersBy("name", match);
- },
- /**
- * APIMethod: getLayersByClass
- * Get a list of layers of a given class (CLASS_NAME).
- *
- * Parameters:
- * match - {String | Object} A layer class name. The match can also be a
- * regular expression literal or object. In addition, it can be any
- * object with a method named test. For reqular expressions or other,
- * if type.test(layer.CLASS_NAME) evaluates to true, the layer will
- * be included in the list of layers returned. If no layers are
- * found, an empty array is returned.
- *
- * Returns:
- * {Array(<OpenLayers.Layer>)} A list of layers matching the given class.
- * An empty array is returned if no matches are found.
- */
- getLayersByClass: function(match) {
- return this.getLayersBy("CLASS_NAME", match);
- },
- /**
- * APIMethod: getControlsBy
- * Get a list of controls with properties matching the given criteria.
- *
- * Parameters:
- * property - {String} A control property to be matched.
- * match - {String | Object} A string to match. Can also be a regular
- * expression literal or object. In addition, it can be any object
- * with a method named test. For reqular expressions or other, if
- * match.test(layer[property]) evaluates to true, the layer will be
- * included in the array returned. If no layers are found, an empty
- * array is returned.
- *
- * Returns:
- * {Array(<OpenLayers.Control>)} A list of controls matching the given
- * criteria. An empty array is returned if no matches are found.
- */
- getControlsBy: function(property, match) {
- return this.getBy("controls", property, match);
- },
- /**
- * APIMethod: getControlsByClass
- * Get a list of controls of a given class (CLASS_NAME).
- *
- * Parameters:
- * match - {String | Object} A control class name. The match can also be a
- * regular expression literal or object. In addition, it can be any
- * object with a method named test. For reqular expressions or other,
- * if type.test(control.CLASS_NAME) evaluates to true, the control will
- * be included in the list of controls returned. If no controls are
- * found, an empty array is returned.
- *
- * Returns:
- * {Array(<OpenLayers.Control>)} A list of controls matching the given class.
- * An empty array is returned if no matches are found.
- */
- getControlsByClass: function(match) {
- return this.getControlsBy("CLASS_NAME", match);
- },
- /********************************************************/
- /* */
- /* Layer Functions */
- /* */
- /* The following functions deal with adding and */
- /* removing Layers to and from the Map */
- /* */
- /********************************************************/
- /**
- * APIMethod: getLayer
- * Get a layer based on its id
- *
- * Parameters:
- * id - {String} A layer id
- *
- * Returns:
- * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's
- * layer collection, or null if not found.
- */
- getLayer: function(id) {
- var foundLayer = null;
- for (var i=0, len=this.layers.length; i<len; i++) {
- var layer = this.layers[i];
- if (layer.id == id) {
- foundLayer = layer;
- break;
- }
- }
- return foundLayer;
- },
- /**
- * Method: setLayerZIndex
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * zIdx - {int}
- */
- setLayerZIndex: function (layer, zIdx) {
- layer.setZIndex(
- this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
- + zIdx * 5 );
- },
- /**
- * Method: resetLayersZIndex
- * Reset each layer's z-index based on layer's array index
- */
- resetLayersZIndex: function() {
- for (var i=0, len=this.layers.length; i<len; i++) {
- var layer = this.layers[i];
- this.setLayerZIndex(layer, i);
- }
- },
- /**
- * APIMethod: addLayer
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- *
- * Returns:
- * {Boolean} True if the layer has been added to the map.
- */
- addLayer: function (layer) {
- for(var i = 0, len = this.layers.length; i < len; i++) {
- if (this.layers[i] == layer) {
- return false;
- }
- }
- if (this.events.triggerEvent("preaddlayer", {layer: layer}) === false) {
- return false;
- }
- if(this.allOverlays) {
- layer.isBaseLayer = false;
- }
-
- layer.div.className = "olLayerDiv";
- layer.div.style.overflow = "";
- this.setLayerZIndex(layer, this.layers.length);
- if (layer.isFixed) {
- this.viewPortDiv.appendChild(layer.div);
- } else {
- this.layerContainerDiv.appendChild(layer.div);
- }
- this.layers.push(layer);
- layer.setMap(this);
- if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) {
- if (this.baseLayer == null) {
- // set the first baselaye we add as the baselayer
- this.setBaseLayer(layer);
- } else {
- layer.setVisibility(false);
- }
- } else {
- layer.redraw();
- }
- this.events.triggerEvent("addlayer", {layer: layer});
- layer.events.triggerEvent("added", {map: this, layer: layer});
- layer.afterAdd();
- return true;
- },
- /**
- * APIMethod: addLayers
- *
- * Parameters:
- * layers - {Array(<OpenLayers.Layer>)}
- */
- addLayers: function (layers) {
- for (var i=0, len=layers.length; i<len; i++) {
- this.addLayer(layers[i]);
- }
- },
- /**
- * APIMethod: removeLayer
- * Removes a layer from the map by removing its visual element (the
- * layer.div property), then removing it from the map's internal list
- * of layers, setting the layer's map property to null.
- *
- * a "removelayer" event is triggered.
- *
- * very worthy of mention is that simply removing a layer from a map
- * will not cause the removal of any popups which may have been created
- * by the layer. this is due to the fact that it was decided at some
- * point that popups would not belong to layers. thus there is no way
- * for us to know here to which layer the popup belongs.
- *
- * A simple solution to this is simply to call destroy() on the layer.
- * the default OpenLayers.Layer class's destroy() function
- * automatically takes care to remove itself from whatever map it has
- * been attached to.
- *
- * The correct solution is for the layer itself to register an
- * event-handler on "removelayer" and when it is called, if it
- * recognizes itself as the layer being removed, then it cycles through
- * its own personal list of popups, removing them from the map.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * setNewBaseLayer - {Boolean} Default is true
- */
- removeLayer: function(layer, setNewBaseLayer) {
- if (this.events.triggerEvent("preremovelayer", {layer: layer}) === false) {
- return;
- }
- if (setNewBaseLayer == null) {
- setNewBaseLayer = true;
- }
- if (layer.isFixed) {
- this.viewPortDiv.removeChild(layer.div);
- } else {
- this.layerContainerDiv.removeChild(layer.div);
- }
- OpenLayers.Util.removeItem(this.layers, layer);
- layer.removeMap(this);
- layer.map = null;
- // if we removed the base layer, need to set a new one
- if(this.baseLayer == layer) {
- this.baseLayer = null;
- if(setNewBaseLayer) {
- for(var i=0, len=this.layers.length; i<len; i++) {
- var iLayer = this.layers[i];
- if (iLayer.isBaseLayer || this.allOverlays) {
- this.setBaseLayer(iLayer);
- break;
- }
- }
- }
- }
- this.resetLayersZIndex();
- this.events.triggerEvent("removelayer", {layer: layer});
- layer.events.triggerEvent("removed", {map: this, layer: layer});
- },
- /**
- * APIMethod: getNumLayers
- *
- * Returns:
- * {Int} The number of layers attached to the map.
- */
- getNumLayers: function () {
- return this.layers.length;
- },
- /**
- * APIMethod: getLayerIndex
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- *
- * Returns:
- * {Integer} The current (zero-based) index of the given layer in the map's
- * layer stack. Returns -1 if the layer isn't on the map.
- */
- getLayerIndex: function (layer) {
- return OpenLayers.Util.indexOf(this.layers, layer);
- },
-
- /**
- * APIMethod: setLayerIndex
- * Move the given layer to the specified (zero-based) index in the layer
- * list, changing its z-index in the map display. Use
- * map.getLayerIndex() to find out the current index of a layer. Note
- * that this cannot (or at least should not) be effectively used to
- * raise base layers above overlays.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * idx - {int}
- */
- setLayerIndex: function (layer, idx) {
- var base = this.getLayerIndex(layer);
- if (idx < 0) {
- idx = 0;
- } else if (idx > this.layers.length) {
- idx = this.layers.length;
- }
- if (base != idx) {
- this.layers.splice(base, 1);
- this.layers.splice(idx, 0, layer);
- for (var i=0, len=this.layers.length; i<len; i++) {
- this.setLayerZIndex(this.layers[i], i);
- }
- this.events.triggerEvent("changelayer", {
- layer: layer, property: "order"
- });
- if(this.allOverlays) {
- if(idx === 0) {
- this.setBaseLayer(layer);
- } else if(this.baseLayer !== this.layers[0]) {
- this.setBaseLayer(this.layers[0]);
- }
- }
- }
- },
- /**
- * APIMethod: raiseLayer
- * Change the index of the given layer by delta. If delta is positive,
- * the layer is moved up the map's layer stack; if delta is negative,
- * the layer is moved down. Again, note that this cannot (or at least
- * should not) be effectively used to raise base layers above overlays.
- *
- * Paremeters:
- * layer - {<OpenLayers.Layer>}
- * delta - {int}
- */
- raiseLayer: function (layer, delta) {
- var idx = this.getLayerIndex(layer) + delta;
- this.setLayerIndex(layer, idx);
- },
-
- /**
- * APIMethod: setBaseLayer
- * Allows user to specify one of the currently-loaded layers as the Map's
- * new base layer.
- *
- * Parameters:
- * newBaseLayer - {<OpenLayers.Layer>}
- */
- setBaseLayer: function(newBaseLayer) {
-
- if (newBaseLayer != this.baseLayer) {
-
- // ensure newBaseLayer is already loaded
- if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
- // preserve center and scale when changing base layers
- var center = this.getCachedCenter();
- var newResolution = OpenLayers.Util.getResolutionFromScale(
- this.getScale(), newBaseLayer.units
- );
- // make the old base layer invisible
- if (this.baseLayer != null && !this.allOverlays) {
- this.baseLayer.setVisibility(false);
- }
- // set new baselayer
- this.baseLayer = newBaseLayer;
-
- if(!this.allOverlays || this.baseLayer.visibility) {
- this.baseLayer.setVisibility(true);
- // Layer may previously have been visible but not in range.
- // In this case we need to redraw it to make it visible.
- if (this.baseLayer.inRange === false) {
- this.baseLayer.redraw();
- }
- }
- // recenter the map
- if (center != null) {
- // new zoom level derived from old scale
- var newZoom = this.getZoomForResolution(
- newResolution || this.resolution, true
- );
- // zoom and force zoom change
- this.setCenter(center, newZoom, false, true);
- }
- this.events.triggerEvent("changebaselayer", {
- layer: this.baseLayer
- });
- }
- }
- },
- /********************************************************/
- /* */
- /* Control Functions */
- /* */
- /* The following functions deal with adding and */
- /* removing Controls to and from the Map */
- /* */
- /********************************************************/
- /**
- * APIMethod: addControl
- * Add the passed over control to the map. Optionally
- * position the control at the given pixel.
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * px - {<OpenLayers.Pixel>}
- */
- addControl: function (control, px) {
- this.controls.push(control);
- this.addControlToMap(control, px);
- },
-
- /**
- * APIMethod: addControls
- * Add all of the passed over controls to the map.
- * You can pass over an optional second array
- * with pixel-objects to position the controls.
- * The indices of the two arrays should match and
- * you can add null as pixel for those controls
- * you want to be autopositioned.
- *
- * Parameters:
- * controls - {Array(<OpenLayers.Control>)}
- * pixels - {Array(<OpenLayers.Pixel>)}
- */
- addControls: function (controls, pixels) {
- var pxs = (arguments.length === 1) ? [] : pixels;
- for (var i=0, len=controls.length; i<len; i++) {
- var ctrl = controls[i];
- var px = (pxs[i]) ? pxs[i] : null;
- this.addControl( ctrl, px );
- }
- },
- /**
- * Method: addControlToMap
- *
- * Parameters:
- *
- * control - {<OpenLayers.Control>}
- * px - {<OpenLayers.Pixel>}
- */
- addControlToMap: function (control, px) {
- // If a control doesn't have a div at this point, it belongs in the
- // viewport.
- control.outsideViewport = (control.div != null);
-
- // If the map has a displayProjection, and the control doesn't, set
- // the display projection.
- if (this.displayProjection && !control.displayProjection) {
- control.displayProjection = this.displayProjection;
- }
-
- control.setMap(this);
- var div = control.draw(px);
- if (div) {
- if(!control.outsideViewport) {
- div.style.zIndex = this.Z_INDEX_BASE['Control'] +
- this.controls.length;
- this.viewPortDiv.appendChild( div );
- }
- }
- if(control.autoActivate) {
- control.activate();
- }
- },
-
- /**
- * APIMethod: getControl
- *
- * Parameters:
- * id - {String} ID of the control to return.
- *
- * Returns:
- * {<OpenLayers.Control>} The control from the map's list of controls
- * which has a matching 'id'. If none found,
- * returns null.
- */
- getControl: function (id) {
- var returnControl = null;
- for(var i=0, len=this.controls.length; i<len; i++) {
- var control = this.controls[i];
- if (control.id == id) {
- returnControl = control;
- break;
- }
- }
- return returnControl;
- },
-
- /**
- * APIMethod: removeControl
- * Remove a control from the map. Removes the control both from the map
- * object's internal array of controls, as well as from the map's
- * viewPort (assuming the control was not added outsideViewport)
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control to remove.
- */
- removeControl: function (control) {
- //make sure control is non-null and actually part of our map
- if ( (control) && (control == this.getControl(control.id)) ) {
- if (control.div && (control.div.parentNode == this.viewPortDiv)) {
- this.viewPortDiv.removeChild(control.div);
- }
- OpenLayers.Util.removeItem(this.controls, control);
- }
- },
- /********************************************************/
- /* */
- /* Popup Functions */
- /* */
- /* The following functions deal with adding and */
- /* removing Popups to and from the Map */
- /* */
- /********************************************************/
- /**
- * APIMethod: addPopup
- *
- * Parameters:
- * popup - {<OpenLayers.Popup>}
- * exclusive - {Boolean} If true, closes all other popups first
- */
- addPopup: function(popup, exclusive) {
- if (exclusive) {
- //remove all other popups from screen
- for (var i = this.popups.length - 1; i >= 0; --i) {
- this.removePopup(this.popups[i]);
- }
- }
- popup.map = this;
- this.popups.push(popup);
- var popupDiv = popup.draw();
- if (popupDiv) {
- popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +
- this.popups.length;
- this.layerContainerDiv.appendChild(popupDiv);
- }
- },
-
- /**
- * APIMethod: removePopup
- *
- * Parameters:
- * popup - {<OpenLayers.Popup>}
- */
- removePopup: function(popup) {
- OpenLayers.Util.removeItem(this.popups, popup);
- if (popup.div) {
- try { this.layerContainerDiv.removeChild(popup.div); }
- catch (e) { } // Popups sometimes apparently get disconnected
- // from the layerContainerDiv, and cause complaints.
- }
- popup.map = null;
- },
- /********************************************************/
- /* */
- /* Container Div Functions */
- /* */
- /* The following functions deal with the access to */
- /* and maintenance of the size of the container div */
- /* */
- /********************************************************/
- /**
- * APIMethod: getSize
- *
- * Returns:
- * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the
- * size, in pixels, of the div into which OpenLayers
- * has been loaded.
- * Note - A clone() of this locally cached variable is
- * returned, so as not to allow users to modify it.
- */
- getSize: function () {
- var size = null;
- if (this.size != null) {
- size = this.size.clone();
- }
- return size;
- },
- /**
- * APIMethod: updateSize
- * This function should be called by any external code which dynamically
- * changes the size of the map div (because mozilla wont let us catch
- * the "onresize" for an element)
- */
- updateSize: function() {
- // the div might have moved on the page, also
- var newSize = this.getCurrentSize();
- if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) {
- this.events.clearMouseCache();
- var oldSize = this.getSize();
- if (oldSize == null) {
- this.size = oldSize = newSize;
- }
- if (!newSize.equals(oldSize)) {
-
- // store the new size
- this.size = newSize;
-
- //notify layers of mapresize
- for(var i=0, len=this.layers.length; i<len; i++) {
- this.layers[i].onMapResize();
- }
-
- var center = this.getCachedCenter();
-
- if (this.baseLayer != null && center != null) {
- var zoom = this.getZoom();
- this.zoom = null;
- this.setCenter(center, zoom);
- }
-
- }
- }
- },
-
- /**
- * Method: getCurrentSize
- *
- * Returns:
- * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
- * of the map div
- */
- getCurrentSize: function() {
- var size = new OpenLayers.Size(this.div.clientWidth,
- this.div.clientHeight);
- if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
- size.w = this.div.offsetWidth;
- size.h = this.div.offsetHeight;
- }
- if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
- size.w = parseInt(this.div.style.width);
- size.h = parseInt(this.div.style.height);
- }
- return size;
- },
- /**
- * Method: calculateBounds
- *
- * Parameters:
- * center - {<OpenLayers.LonLat>} Default is this.getCenter()
- * resolution - {float} Default is this.getResolution()
- *
- * Returns:
- * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
- * current mapsize.
- */
- calculateBounds: function(center, resolution) {
- var extent = null;
-
- if (center == null) {
- center = this.getCachedCenter();
- }
- if (resolution == null) {
- resolution = this.getResolution();
- }
-
- if ((center != null) && (resolution != null)) {
- var halfWDeg = (this.size.w * resolution) / 2;
- var halfHDeg = (this.size.h * resolution) / 2;
-
- extent = new OpenLayers.Bounds(center.lon - halfWDeg,
- center.lat - halfHDeg,
- center.lon + halfWDeg,
- center.lat + halfHDeg);
- }
- return extent;
- },
- /********************************************************/
- /* */
- /* Zoom, Center, Pan Functions */
- /* */
- /* The following functions handle the validation, */
- /* getting and setting of the Zoom Level and Center */
- /* as well as the panning of the Map */
- /* */
- /********************************************************/
- /**
- * APIMethod: getCenter
- *
- * Returns:
- * {<OpenLayers.LonLat>}
- */
- getCenter: function () {
- var center = null;
- var cachedCenter = this.getCachedCenter();
- if (cachedCenter) {
- center = cachedCenter.clone();
- }
- return center;
- },
- /**
- * Method: getCachedCenter
- *
- * Returns:
- * {<OpenLayers.LonLat>}
- */
- getCachedCenter: function() {
- if (!this.center && this.size) {
- this.center = this.getLonLatFromViewPortPx({
- x: this.size.w / 2,
- y: this.size.h / 2
- });
- }
- return this.center;
- },
- /**
- * APIMethod: getZoom
- *
- * Returns:
- * {Integer}
- */
- getZoom: function () {
- return this.zoom;
- },
-
- /**
- * APIMethod: pan
- * Allows user to pan by a value of screen pixels
- *
- * Parameters:
- * dx - {Integer}
- * dy - {Integer}
- * options - {Object} Options to configure panning:
- * - *animate* {Boolean} Use panTo instead of setCenter. Default is true.
- * - *dragging* {Boolean} Call setCenter with dragging true. Default is
- * false.
- */
- pan: function(dx, dy, options) {
- options = OpenLayers.Util.applyDefaults(options, {
- animate: true,
- dragging: false
- });
- if (options.dragging) {
- if (dx != 0 || dy != 0) {
- this.moveByPx(dx, dy);
- }
- } else {
- // getCenter
- var centerPx = this.getViewPortPxFromLonLat(this.getCachedCenter());
- // adjust
- var newCenterPx = centerPx.add(dx, dy);
- if (this.dragging || !newCenterPx.equals(centerPx)) {
- var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
- if (options.animate) {
- this.panTo(newCenterLonLat);
- } else {
- this.moveTo(newCenterLonLat);
- if(this.dragging) {
- this.dragging = false;
- this.events.triggerEvent("moveend");
- }
- }
- }
- }
- },
-
- /**
- * APIMethod: panTo
- * Allows user to pan to a new lonlat
- * If the new lonlat is in the current extent the map will slide smoothly
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- */
- panTo: function(lonlat) {
- if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) {
- if (!this.panTween) {
- this.panTween = new OpenLayers.Tween(this.panMethod);
- }
- var center = this.getCachedCenter();
- // center will not change, don't do nothing
- if (lonlat.equals(center)) {
- return;
- }
- var from = this.getPixelFromLonLat(center);
- var to = this.getPixelFromLonLat(lonlat);
- var vector = { x: to.x - from.x, y: to.y - from.y };
- var last = { x: 0, y: 0 };
- this.panTween.start( { x: 0, y: 0 }, vector, this.panDuration, {
- callbacks: {
- eachStep: OpenLayers.Function.bind(function(px) {
- var x = px.x - last.x,
- y = px.y - last.y;
- this.moveByPx(x, y);
- last.x = Math.round(px.x);
- last.y = Math.round(px.y);
- }, this),
- done: OpenLayers.Function.bind(function(px) {
- this.moveTo(lonlat);
- this.dragging = false;
- this.events.triggerEvent("moveend");
- }, this)
- }
- });
- } else {
- this.setCenter(lonlat);
- }
- },
- /**
- * APIMethod: setCenter
- * Set the map center (and optionally, the zoom level).
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>|Array} The new center location.
- * If provided as array, the first value is the x coordinate,
- * and the 2nd value is the y coordinate.
- * zoom - {Integer} Optional zoom level.
- * dragging - {Boolean} Specifies whether or not to trigger
- * movestart/end events
- * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom
- * change events (needed on baseLayer change)
- *
- * TBD: reconsider forceZoomChange in 3.0
- */
- setCenter: function(lonlat, zoom, dragging, forceZoomChange) {
- this.panTween && this.panTween.stop();
- this.moveTo(lonlat, zoom, {
- 'dragging': dragging,
- 'forceZoomChange': forceZoomChange
- });
- },
-
- /**
- * Method: moveByPx
- * Drag the map by pixels.
- *
- * Parameters:
- * dx - {Number}
- * dy - {Number}
- */
- moveByPx: function(dx, dy) {
- var hw = this.size.w / 2;
- var hh = this.size.h / 2;
- var x = hw + dx;
- var y = hh + dy;
- var wrapDateLine = this.baseLayer.wrapDateLine;
- var xRestriction = 0;
- var yRestriction = 0;
- if (this.restrictedExtent) {
- xRestriction = hw;
- yRestriction = hh;
- // wrapping the date line makes no sense for restricted extents
- wrapDateLine = false;
- }
- dx = wrapDateLine ||
- x <= this.maxPx.x - xRestriction &&
- x >= this.minPx.x + xRestriction ? Math.round(dx) : 0;
- dy = y <= this.maxPx.y - yRestriction &&
- y >= this.minPx.y + yRestriction ? Math.round(dy) : 0;
- if (dx || dy) {
- if (!this.dragging) {
- this.dragging = true;
- this.events.triggerEvent("movestart");
- }
- this.center = null;
- if (dx) {
- this.layerContainerDiv.style.left =
- parseInt(this.layerContainerDiv.style.left) - dx + "px";
- this.minPx.x -= dx;
- this.maxPx.x -= dx;
- }
- if (dy) {
- this.layerContainerDiv.style.top =
- parseInt(this.layerContainerDiv.style.top) - dy + "px";
- this.minPx.y -= dy;
- this.maxPx.y -= dy;
- }
- var layer, i, len;
- for (i=0, len=this.layers.length; i<len; ++i) {
- layer = this.layers[i];
- if (layer.visibility &&
- (layer === this.baseLayer || layer.inRange)) {
- layer.moveByPx(dx, dy);
- layer.events.triggerEvent("move");
- }
- }
- this.events.triggerEvent("move");
- }
- },
-
- /**
- * Method: adjustZoom
- *
- * Parameters:
- * zoom - {Number} The zoom level to adjust
- *
- * Returns:
- * {Integer} Adjusted zoom level that shows a map not wider than its
- * <baseLayer>'s maxExtent.
- */
- adjustZoom: function(zoom) {
- var resolution, resolutions = this.baseLayer.resolutions,
- maxResolution = this.getMaxExtent().getWidth() / this.size.w;
- if (this.getResolutionForZoom(zoom) > maxResolution) {
- for (var i=zoom|0, ii=resolutions.length; i<ii; ++i) {
- if (resolutions[i] <= maxResolution) {
- zoom = i;
- break;
- }
- }
- }
- return zoom;
- },
- /**
- * Method: moveTo
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- * zoom - {Integer}
- * options - {Object}
- */
- moveTo: function(lonlat, zoom, options) {
- if (lonlat != null && !(lonlat instanceof OpenLayers.LonLat)) {
- lonlat = new OpenLayers.LonLat(lonlat);
- }
- if (!options) {
- options = {};
- }
- if (zoom != null) {
- zoom = parseFloat(zoom);
- if (!this.fractionalZoom) {
- zoom = Math.round(zoom);
- }
- }
- if (this.baseLayer.wrapDateLine) {
- var requestedZoom = zoom;
- zoom = this.adjustZoom(zoom);
- if (zoom !== requestedZoom) {
- // zoom was adjusted, so keep old lonlat to avoid panning
- lonlat = this.getCenter();
- }
- }
- // dragging is false by default
- var dragging = options.dragging || this.dragging;
- // forceZoomChange is false by default
- var forceZoomChange = options.forceZoomChange;
- if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) {
- lonlat = this.maxExtent.getCenterLonLat();
- this.center = lonlat.clone();
- }
- if(this.restrictedExtent != null) {
- // In 3.0, decide if we want to change interpretation of maxExtent.
- if(lonlat == null) {
- lonlat = this.center;
- }
- if(zoom == null) {
- zoom = this.getZoom();
- }
- var resolution = this.getResolutionForZoom(zoom);
- var extent = this.calculateBounds(lonlat, resolution);
- if(!this.restrictedExtent.containsBounds(extent)) {
- var maxCenter = this.restrictedExtent.getCenterLonLat();
- if(extent.getWidth() > this.restrictedExtent.getWidth()) {
- lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat);
- } else if(extent.left < this.restrictedExtent.left) {
- lonlat = lonlat.add(this.restrictedExtent.left -
- extent.left, 0);
- } else if(extent.right > this.restrictedExtent.right) {
- lonlat = lonlat.add(this.restrictedExtent.right -
- extent.right, 0);
- }
- if(extent.getHeight() > this.restrictedExtent.getHeight()) {
- lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat);
- } else if(extent.bottom < this.restrictedExtent.bottom) {
- lonlat = lonlat.add(0, this.restrictedExtent.bottom -
- extent.bottom);
- }
- else if(extent.top > this.restrictedExtent.top) {
- lonlat = lonlat.add(0, this.restrictedExtent.top -
- extent.top);
- }
- }
- }
-
- var zoomChanged = forceZoomChange || (
- (this.isValidZoomLevel(zoom)) &&
- (zoom != this.getZoom()) );
- var centerChanged = (this.isValidLonLat(lonlat)) &&
- (!lonlat.equals(this.center));
- // if neither center nor zoom will change, no need to do anything
- if (zoomChanged || centerChanged || dragging) {
- dragging || this.events.triggerEvent("movestart");
- if (centerChanged) {
- if (!zoomChanged && this.center) {
- // if zoom hasnt changed, just slide layerContainer
- // (must be done before setting this.center to new value)
- this.centerLayerContainer(lonlat);
- }
- this.center = lonlat.clone();
- }
- var res = zoomChanged ?
- this.getResolutionForZoom(zoom) : this.getResolution();
- // (re)set the layerContainerDiv's location
- if (zoomChanged || this.layerContainerOrigin == null) {
- this.layerContainerOrigin = this.getCachedCenter();
- this.layerContainerDiv.style.left = "0px";
- this.layerContainerDiv.style.top = "0px";
- var maxExtent = this.getMaxExtent({restricted: true});
- var maxExtentCenter = maxExtent.getCenterLonLat();
- var lonDelta = this.center.lon - maxExtentCenter.lon;
- var latDelta = maxExtentCenter.lat - this.center.lat;
- var extentWidth = Math.round(maxExtent.getWidth() / res);
- var extentHeight = Math.round(maxExtent.getHeight() / res);
- this.minPx = {
- x: (this.size.w - extentWidth) / 2 - lonDelta / res,
- y: (this.size.h - extentHeight) / 2 - latDelta / res
- };
- this.maxPx = {
- x: this.minPx.x + Math.round(maxExtent.getWidth() / res),
- y: this.minPx.y + Math.round(maxExtent.getHeight() / res)
- };
- }
- if (zoomChanged) {
- this.zoom = zoom;
- this.resolution = res;
- }
-
- var bounds = this.getExtent();
-
- //send the move call to the baselayer and all the overlays
- if(this.baseLayer.visibility) {
- this.baseLayer.moveTo(bounds, zoomChanged, options.dragging);
- options.dragging || this.baseLayer.events.triggerEvent(
- "moveend", {zoomChanged: zoomChanged}
- );
- }
-
- bounds = this.baseLayer.getExtent();
-
- for (var i=this.layers.length-1; i>=0; --i) {
- var layer = this.layers[i];
- if (layer !== this.baseLayer && !layer.isBaseLayer) {
- var inRange = layer.calculateInRange();
- if (layer.inRange != inRange) {
- // the inRange property has changed. If the layer is
- // no longer in range, we turn it off right away. If
- // the layer is no longer out of range, the moveTo
- // call below will turn on the layer.
- layer.inRange = inRange;
- if (!inRange) {
- layer.display(false);
- }
- this.events.triggerEvent("changelayer", {
- layer: layer, property: "visibility"
- });
- }
- if (inRange && layer.visibility) {
- layer.moveTo(bounds, zoomChanged, options.dragging);
- options.dragging || layer.events.triggerEvent(
- "moveend", {zoomChanged: zoomChanged}
- );
- }
- }
- }
-
- this.events.triggerEvent("move");
- dragging || this.events.triggerEvent("moveend");
- if (zoomChanged) {
- //redraw popups
- for (var i=0, len=this.popups.length; i<len; i++) {
- this.popups[i].updatePosition();
- }
- this.events.triggerEvent("zoomend");
- }
- }
- },
- /**
- * Method: centerLayerContainer
- * This function takes care to recenter the layerContainerDiv.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- */
- centerLayerContainer: function (lonlat) {
- var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
- var newPx = this.getViewPortPxFromLonLat(lonlat);
- if ((originPx != null) && (newPx != null)) {
- var oldLeft = parseInt(this.layerContainerDiv.style.left);
- var oldTop = parseInt(this.layerContainerDiv.style.top);
- var newLeft = Math.round(originPx.x - newPx.x);
- var newTop = Math.round(originPx.y - newPx.y);
- this.layerContainerDiv.style.left = newLeft + "px";
- this.layerContainerDiv.style.top = newTop + "px";
- var dx = oldLeft - newLeft;
- var dy = oldTop - newTop;
- this.minPx.x -= dx;
- this.maxPx.x -= dx;
- this.minPx.y -= dy;
- this.maxPx.y -= dy;
- }
- },
- /**
- * Method: isValidZoomLevel
- *
- * Parameters:
- * zoomLevel - {Integer}
- *
- * Returns:
- * {Boolean} Whether or not the zoom level passed in is non-null and
- * within the min/max range of zoom levels.
- */
- isValidZoomLevel: function(zoomLevel) {
- return ( (zoomLevel != null) &&
- (zoomLevel >= 0) &&
- (zoomLevel < this.getNumZoomLevels()) );
- },
-
- /**
- * Method: isValidLonLat
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {Boolean} Whether or not the lonlat passed in is non-null and within
- * the maxExtent bounds
- */
- isValidLonLat: function(lonlat) {
- var valid = false;
- if (lonlat != null) {
- var maxExtent = this.getMaxExtent();
- var worldBounds = this.baseLayer.wrapDateLine && maxExtent;
- valid = maxExtent.containsLonLat(lonlat, {worldBounds: worldBounds});
- }
- return valid;
- },
- /********************************************************/
- /* */
- /* Layer Options */
- /* */
- /* Accessor functions to Layer Options parameters */
- /* */
- /********************************************************/
-
- /**
- * APIMethod: getProjection
- * This method returns a string representing the projection. In
- * the case of projection support, this will be the srsCode which
- * is loaded -- otherwise it will simply be the string value that
- * was passed to the projection at startup.
- *
- * FIXME: In 3.0, we will remove getProjectionObject, and instead
- * return a Projection object from this function.
- *
- * Returns:
- * {String} The Projection string from the base layer or null.
- */
- getProjection: function() {
- var projection = this.getProjectionObject();
- return projection ? projection.getCode() : null;
- },
-
- /**
- * APIMethod: getProjectionObject
- * Returns the projection obect from the baselayer.
- *
- * Returns:
- * {<OpenLayers.Projection>} The Projection of the base layer.
- */
- getProjectionObject: function() {
- var projection = null;
- if (this.baseLayer != null) {
- projection = this.baseLayer.projection;
- }
- return projection;
- },
-
- /**
- * APIMethod: getMaxResolution
- *
- * Returns:
- * {String} The Map's Maximum Resolution
- */
- getMaxResolution: function() {
- var maxResolution = null;
- if (this.baseLayer != null) {
- maxResolution = this.baseLayer.maxResolution;
- }
- return maxResolution;
- },
-
- /**
- * APIMethod: getMaxExtent
- *
- * Parameters:
- * options - {Object}
- *
- * Allowed Options:
- * restricted - {Boolean} If true, returns restricted extent (if it is
- * available.)
- *
- * Returns:
- * {<OpenLayers.Bounds>} The maxExtent property as set on the current
- * baselayer, unless the 'restricted' option is set, in which case
- * the 'restrictedExtent' option from the map is returned (if it
- * is set).
- */
- getMaxExtent: function (options) {
- var maxExtent = null;
- if(options && options.restricted && this.restrictedExtent){
- maxExtent = this.restrictedExtent;
- } else if (this.baseLayer != null) {
- maxExtent = this.baseLayer.maxExtent;
- }
- return maxExtent;
- },
-
- /**
- * APIMethod: getNumZoomLevels
- *
- * Returns:
- * {Integer} The total number of zoom levels that can be displayed by the
- * current baseLayer.
- */
- getNumZoomLevels: function() {
- var numZoomLevels = null;
- if (this.baseLayer != null) {
- numZoomLevels = this.baseLayer.numZoomLevels;
- }
- return numZoomLevels;
- },
- /********************************************************/
- /* */
- /* Baselayer Functions */
- /* */
- /* The following functions, all publicly exposed */
- /* in the API?, are all merely wrappers to the */
- /* the same calls on whatever layer is set as */
- /* the current base layer */
- /* */
- /********************************************************/
- /**
- * APIMethod: getExtent
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
- * bounds of the current viewPort.
- * If no baselayer is set, returns null.
- */
- getExtent: function () {
- var extent = null;
- if (this.baseLayer != null) {
- extent = this.baseLayer.getExtent();
- }
- return extent;
- },
- /**
- * APIMethod: getResolution
- *
- * Returns:
- * {Float} The current resolution of the map.
- * If no baselayer is set, returns null.
- */
- getResolution: function () {
- var resolution = null;
- if (this.baseLayer != null) {
- resolution = this.baseLayer.getResolution();
- } else if(this.allOverlays === true && this.layers.length > 0) {
- // while adding the 1st layer to the map in allOverlays mode,
- // this.baseLayer is not set yet when we need the resolution
- // for calculateInRange.
- resolution = this.layers[0].getResolution();
- }
- return resolution;
- },
- /**
- * APIMethod: getUnits
- *
- * Returns:
- * {Float} The current units of the map.
- * If no baselayer is set, returns null.
- */
- getUnits: function () {
- var units = null;
- if (this.baseLayer != null) {
- units = this.baseLayer.units;
- }
- return units;
- },
- /**
- * APIMethod: getScale
- *
- * Returns:
- * {Float} The current scale denominator of the map.
- * If no baselayer is set, returns null.
- */
- getScale: function () {
- var scale = null;
- if (this.baseLayer != null) {
- var res = this.getResolution();
- var units = this.baseLayer.units;
- scale = OpenLayers.Util.getScaleFromResolution(res, units);
- }
- return scale;
- },
- /**
- * APIMethod: getZoomForExtent
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * closest - {Boolean} Find the zoom level that most closely fits the
- * specified bounds. Note that this may result in a zoom that does
- * not exactly contain the entire extent.
- * Default is false.
- *
- * Returns:
- * {Integer} A suitable zoom level for the specified bounds.
- * If no baselayer is set, returns null.
- */
- getZoomForExtent: function (bounds, closest) {
- var zoom = null;
- if (this.baseLayer != null) {
- zoom = this.baseLayer.getZoomForExtent(bounds, closest);
- }
- return zoom;
- },
- /**
- * APIMethod: getResolutionForZoom
- *
- * Parameters:
- * zoom - {Float}
- *
- * Returns:
- * {Float} A suitable resolution for the specified zoom. If no baselayer
- * is set, returns null.
- */
- getResolutionForZoom: function(zoom) {
- var resolution = null;
- if(this.baseLayer) {
- resolution = this.baseLayer.getResolutionForZoom(zoom);
- }
- return resolution;
- },
- /**
- * APIMethod: getZoomForResolution
- *
- * Parameters:
- * resolution - {Float}
- * closest - {Boolean} Find the zoom level that corresponds to the absolute
- * closest resolution, which may result in a zoom whose corresponding
- * resolution is actually smaller than we would have desired (if this
- * is being called from a getZoomForExtent() call, then this means that
- * the returned zoom index might not actually contain the entire
- * extent specified... but it'll be close).
- * Default is false.
- *
- * Returns:
- * {Integer} A suitable zoom level for the specified resolution.
- * If no baselayer is set, returns null.
- */
- getZoomForResolution: function(resolution, closest) {
- var zoom = null;
- if (this.baseLayer != null) {
- zoom = this.baseLayer.getZoomForResolution(resolution, closest);
- }
- return zoom;
- },
- /********************************************************/
- /* */
- /* Zooming Functions */
- /* */
- /* The following functions, all publicly exposed */
- /* in the API, are all merely wrappers to the */
- /* the setCenter() function */
- /* */
- /********************************************************/
-
- /**
- * APIMethod: zoomTo
- * Zoom to a specific zoom level
- *
- * Parameters:
- * zoom - {Integer}
- */
- zoomTo: function(zoom) {
- if (this.isValidZoomLevel(zoom)) {
- this.setCenter(null, zoom);
- }
- },
-
- /**
- * APIMethod: zoomIn
- *
- */
- zoomIn: function() {
- this.zoomTo(this.getZoom() + 1);
- },
-
- /**
- * APIMethod: zoomOut
- *
- */
- zoomOut: function() {
- this.zoomTo(this.getZoom() - 1);
- },
- /**
- * APIMethod: zoomToExtent
- * Zoom to the passed in bounds, recenter
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * closest - {Boolean} Find the zoom level that most closely fits the
- * specified bounds. Note that this may result in a zoom that does
- * not exactly contain the entire extent.
- * Default is false.
- *
- */
- zoomToExtent: function(bounds, closest) {
- if (!(bounds instanceof OpenLayers.Bounds)) {
- bounds = new OpenLayers.Bounds(bounds);
- }
- var center = bounds.getCenterLonLat();
- if (this.baseLayer.wrapDateLine) {
- var maxExtent = this.getMaxExtent();
- //fix straddling bounds (in the case of a bbox that straddles the
- // dateline, it's left and right boundaries will appear backwards.
- // we fix this by allowing a right value that is greater than the
- // max value at the dateline -- this allows us to pass a valid
- // bounds to calculate zoom)
- //
- bounds = bounds.clone();
- while (bounds.right < bounds.left) {
- bounds.right += maxExtent.getWidth();
- }
- //if the bounds was straddling (see above), then the center point
- // we got from it was wrong. So we take our new bounds and ask it
- // for the center.
- //
- center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
- }
- this.setCenter(center, this.getZoomForExtent(bounds, closest));
- },
- /**
- * APIMethod: zoomToMaxExtent
- * Zoom to the full extent and recenter.
- *
- * Parameters:
- * options - {Object}
- *
- * Allowed Options:
- * restricted - {Boolean} True to zoom to restricted extent if it is
- * set. Defaults to true.
- */
- zoomToMaxExtent: function(options) {
- //restricted is true by default
- var restricted = (options) ? options.restricted : true;
- var maxExtent = this.getMaxExtent({
- 'restricted': restricted
- });
- this.zoomToExtent(maxExtent);
- },
- /**
- * APIMethod: zoomToScale
- * Zoom to a specified scale
- *
- * Parameters:
- * scale - {float}
- * closest - {Boolean} Find the zoom level that most closely fits the
- * specified scale. Note that this may result in a zoom that does
- * not exactly contain the entire extent.
- * Default is false.
- *
- */
- zoomToScale: function(scale, closest) {
- var res = OpenLayers.Util.getResolutionFromScale(scale,
- this.baseLayer.units);
- var halfWDeg = (this.size.w * res) / 2;
- var halfHDeg = (this.size.h * res) / 2;
- var center = this.getCachedCenter();
- var extent = new OpenLayers.Bounds(center.lon - halfWDeg,
- center.lat - halfHDeg,
- center.lon + halfWDeg,
- center.lat + halfHDeg);
- this.zoomToExtent(extent, closest);
- },
-
- /********************************************************/
- /* */
- /* Translation Functions */
- /* */
- /* The following functions translate between */
- /* LonLat, LayerPx, and ViewPortPx */
- /* */
- /********************************************************/
-
- //
- // TRANSLATION: LonLat <-> ViewPortPx
- //
- /**
- * Method: getLonLatFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or
- * an object with a 'x'
- * and 'y' properties.
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
- * port <OpenLayers.Pixel>, translated into lon/lat
- * by the current base layer.
- */
- getLonLatFromViewPortPx: function (viewPortPx) {
- var lonlat = null;
- if (this.baseLayer != null) {
- lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
- }
- return lonlat;
- },
- /**
- * APIMethod: getViewPortPxFromLonLat
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * <OpenLayers.LonLat>, translated into view port
- * pixels by the current base layer.
- */
- getViewPortPxFromLonLat: function (lonlat) {
- var px = null;
- if (this.baseLayer != null) {
- px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
- }
- return px;
- },
-
- //
- // CONVENIENCE TRANSLATION FUNCTIONS FOR API
- //
- /**
- * APIMethod: getLonLatFromPixel
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
- * a 'x' and 'y' properties.
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
- * OpenLayers.Pixel, translated into lon/lat by the
- * current base layer
- */
- getLonLatFromPixel: function (px) {
- return this.getLonLatFromViewPortPx(px);
- },
- /**
- * APIMethod: getPixelFromLonLat
- * Returns a pixel location given a map location. The map location is
- * translated to an integer pixel location (in viewport pixel
- * coordinates) by the current base layer.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>} A map location.
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
- * <OpenLayers.LonLat> translated into view port pixels by the current
- * base layer.
- */
- getPixelFromLonLat: function (lonlat) {
- var px = this.getViewPortPxFromLonLat(lonlat);
- px.x = Math.round(px.x);
- px.y = Math.round(px.y);
- return px;
- },
-
- /**
- * Method: getGeodesicPixelSize
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>} The pixel to get the geodesic length for. If
- * not provided, the center pixel of the map viewport will be used.
- *
- * Returns:
- * {<OpenLayers.Size>} The geodesic size of the pixel in kilometers.
- */
- getGeodesicPixelSize: function(px) {
- var lonlat = px ? this.getLonLatFromPixel(px) : (
- this.getCachedCenter() || new OpenLayers.LonLat(0, 0));
- var res = this.getResolution();
- var left = lonlat.add(-res / 2, 0);
- var right = lonlat.add(res / 2, 0);
- var bottom = lonlat.add(0, -res / 2);
- var top = lonlat.add(0, res / 2);
- var dest = new OpenLayers.Projection("EPSG:4326");
- var source = this.getProjectionObject() || dest;
- if(!source.equals(dest)) {
- left.transform(source, dest);
- right.transform(source, dest);
- bottom.transform(source, dest);
- top.transform(source, dest);
- }
-
- return new OpenLayers.Size(
- OpenLayers.Util.distVincenty(left, right),
- OpenLayers.Util.distVincenty(bottom, top)
- );
- },
- //
- // TRANSLATION: ViewPortPx <-> LayerPx
- //
- /**
- * APIMethod: getViewPortPxFromLayerPx
- *
- * Parameters:
- * layerPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
- * coordinates
- */
- getViewPortPxFromLayerPx:function(layerPx) {
- var viewPortPx = null;
- if (layerPx != null) {
- var dX = parseInt(this.layerContainerDiv.style.left);
- var dY = parseInt(this.layerContainerDiv.style.top);
- viewPortPx = layerPx.add(dX, dY);
- }
- return viewPortPx;
- },
-
- /**
- * APIMethod: getLayerPxFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
- * coordinates
- */
- getLayerPxFromViewPortPx:function(viewPortPx) {
- var layerPx = null;
- if (viewPortPx != null) {
- var dX = -parseInt(this.layerContainerDiv.style.left);
- var dY = -parseInt(this.layerContainerDiv.style.top);
- layerPx = viewPortPx.add(dX, dY);
- if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
- layerPx = null;
- }
- }
- return layerPx;
- },
-
- //
- // TRANSLATION: LonLat <-> LayerPx
- //
- /**
- * Method: getLonLatFromLayerPx
- *
- * Parameters:
- * px - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>}
- */
- getLonLatFromLayerPx: function (px) {
- //adjust for displacement of layerContainerDiv
- px = this.getViewPortPxFromLayerPx(px);
- return this.getLonLatFromViewPortPx(px);
- },
-
- /**
- * APIMethod: getLayerPxFromLonLat
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>} lonlat
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * <OpenLayers.LonLat>, translated into layer pixels
- * by the current base layer
- */
- getLayerPxFromLonLat: function (lonlat) {
- //adjust for displacement of layerContainerDiv
- var px = this.getPixelFromLonLat(lonlat);
- return this.getLayerPxFromViewPortPx(px);
- },
- CLASS_NAME: "OpenLayers.Map"
- });
- /**
- * Constant: TILE_WIDTH
- * {Integer} 256 Default tile width (unless otherwise specified)
- */
- OpenLayers.Map.TILE_WIDTH = 256;
- /**
- * Constant: TILE_HEIGHT
- * {Integer} 256 Default tile height (unless otherwise specified)
- */
- OpenLayers.Map.TILE_HEIGHT = 256;
- /* ======================================================================
- OpenLayers/Layer.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Map.js
- * @requires OpenLayers/Projection.js
- */
- /**
- * Class: OpenLayers.Layer
- */
- OpenLayers.Layer = OpenLayers.Class({
- /**
- * APIProperty: id
- * {String}
- */
- id: null,
- /**
- * APIProperty: name
- * {String}
- */
- name: null,
- /**
- * APIProperty: div
- * {DOMElement}
- */
- div: null,
- /**
- * APIProperty: opacity
- * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default
- * is 1.
- */
- opacity: 1,
- /**
- * APIProperty: alwaysInRange
- * {Boolean} If a layer's display should not be scale-based, this should
- * be set to true. This will cause the layer, as an overlay, to always
- * be 'active', by always returning true from the calculateInRange()
- * function.
- *
- * If not explicitly specified for a layer, its value will be
- * determined on startup in initResolutions() based on whether or not
- * any scale-specific properties have been set as options on the
- * layer. If no scale-specific options have been set on the layer, we
- * assume that it should always be in range.
- *
- * See #987 for more info.
- */
- alwaysInRange: null,
- /**
- * Constant: RESOLUTION_PROPERTIES
- * {Array} The properties that are used for calculating resolutions
- * information.
- */
- RESOLUTION_PROPERTIES: [
- 'scales', 'resolutions',
- 'maxScale', 'minScale',
- 'maxResolution', 'minResolution',
- 'numZoomLevels', 'maxZoomLevel'
- ],
- /**
- * APIProperty: events
- * {<OpenLayers.Events>}
- *
- * Register a listener for a particular event with the following syntax:
- * (code)
- * layer.events.register(type, obj, listener);
- * (end)
- *
- * Listeners will be called with a reference to an event object. The
- * properties of this event depends on exactly what happened.
- *
- * All event objects have at least the following properties:
- * object - {Object} A reference to layer.events.object.
- * element - {DOMElement} A reference to layer.events.element.
- *
- * Supported map event types:
- * loadstart - Triggered when layer loading starts.
- * loadend - Triggered when layer loading ends.
- * visibilitychanged - Triggered when layer visibility is changed.
- * move - Triggered when layer moves (triggered with every mousemove
- * during a drag).
- * moveend - Triggered when layer is done moving, object passed as
- * argument has a zoomChanged boolean property which tells that the
- * zoom has changed.
- * added - Triggered after the layer is added to a map. Listeners will
- * receive an object with a *map* property referencing the map and a
- * *layer* property referencing the layer.
- * removed - Triggered after the layer is removed from the map. Listeners
- * will receive an object with a *map* property referencing the map and
- * a *layer* property referencing the layer.
- */
- events: null,
- /**
- * APIProperty: map
- * {<OpenLayers.Map>} This variable is set when the layer is added to
- * the map, via the accessor function setMap().
- */
- map: null,
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Whether or not the layer is a base layer. This should be set
- * individually by all subclasses. Default is false
- */
- isBaseLayer: false,
-
- /**
- * Property: alpha
- * {Boolean} The layer's images have an alpha channel. Default is false.
- */
- alpha: false,
- /**
- * APIProperty: displayInLayerSwitcher
- * {Boolean} Display the layer's name in the layer switcher. Default is
- * true.
- */
- displayInLayerSwitcher: true,
- /**
- * APIProperty: visibility
- * {Boolean} The layer should be displayed in the map. Default is true.
- */
- visibility: true,
- /**
- * APIProperty: attribution
- * {String} Attribution string, displayed when an
- * <OpenLayers.Control.Attribution> has been added to the map.
- */
- attribution: null,
- /**
- * Property: inRange
- * {Boolean} The current map resolution is within the layer's min/max
- * range. This is set in <OpenLayers.Map.setCenter> whenever the zoom
- * changes.
- */
- inRange: false,
-
- /**
- * Propery: imageSize
- * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
- * the tile by twice the gutter in each dimension.
- */
- imageSize: null,
-
- // OPTIONS
- /**
- * Property: options
- * {Object} An optional object whose properties will be set on the layer.
- * Any of the layer properties can be set as a property of the options
- * object and sent to the constructor when the layer is created.
- */
- options: null,
- /**
- * APIProperty: eventListeners
- * {Object} If set as an option at construction, the eventListeners
- * object will be registered with <OpenLayers.Events.on>. Object
- * structure must be a listeners object as shown in the example for
- * the events.on method.
- */
- eventListeners: null,
- /**
- * APIProperty: gutter
- * {Integer} Determines the width (in pixels) of the gutter around image
- * tiles to ignore. By setting this property to a non-zero value,
- * images will be requested that are wider and taller than the tile
- * size by a value of 2 x gutter. This allows artifacts of rendering
- * at tile edges to be ignored. Set a gutter value that is equal to
- * half the size of the widest symbol that needs to be displayed.
- * Defaults to zero. Non-tiled layers always have zero gutter.
- */
- gutter: 0,
- /**
- * APIProperty: projection
- * {<OpenLayers.Projection>} or {<String>} Specifies the projection of the layer.
- * Can be set in the layer options. If not specified in the layer options,
- * it is set to the default projection specified in the map,
- * when the layer is added to the map.
- * Projection along with default maxExtent and resolutions
- * are set automatically with commercial baselayers in EPSG:3857,
- * such as Google, Bing and OpenStreetMap, and do not need to be specified.
- * Otherwise, if specifying projection, also set maxExtent,
- * maxResolution or resolutions as appropriate.
- * When using vector layers with strategies, layer projection should be set
- * to the projection of the source data if that is different from the map default.
- *
- * Can be either a string or an <OpenLayers.Projection> object;
- * if a string is passed, will be converted to an object when
- * the layer is added to the map.
- *
- */
- projection: null,
-
- /**
- * APIProperty: units
- * {String} The layer map units. Defaults to null. Possible values
- * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
- * Normally taken from the projection.
- * Only required if both map and layers do not define a projection,
- * or if they define a projection which does not define units.
- */
- units: null,
- /**
- * APIProperty: scales
- * {Array} An array of map scales in descending order. The values in the
- * array correspond to the map scale denominator. Note that these
- * values only make sense if the display (monitor) resolution of the
- * client is correctly guessed by whomever is configuring the
- * application. In addition, the units property must also be set.
- * Use <resolutions> instead wherever possible.
- */
- scales: null,
- /**
- * APIProperty: resolutions
- * {Array} A list of map resolutions (map units per pixel) in descending
- * order. If this is not set in the layer constructor, it will be set
- * based on other resolution related properties (maxExtent,
- * maxResolution, maxScale, etc.).
- */
- resolutions: null,
-
- /**
- * APIProperty: maxExtent
- * {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * The maximum extent for the layer. Defaults to null.
- *
- * The center of these bounds will not stray outside
- * of the viewport extent during panning. In addition, if
- * <displayOutsideMaxExtent> is set to false, data will not be
- * requested that falls completely outside of these bounds.
- */
- maxExtent: null,
-
- /**
- * APIProperty: minExtent
- * {<OpenLayers.Bounds>|Array} If provided as an array, the array
- * should consist of four values (left, bottom, right, top).
- * The minimum extent for the layer. Defaults to null.
- */
- minExtent: null,
-
- /**
- * APIProperty: maxResolution
- * {Float} Default max is 360 deg / 256 px, which corresponds to
- * zoom level 0 on gmaps. Specify a different value in the layer
- * options if you are not using the default <OpenLayers.Map.tileSize>
- * and displaying the whole world.
- */
- maxResolution: null,
- /**
- * APIProperty: minResolution
- * {Float}
- */
- minResolution: null,
- /**
- * APIProperty: numZoomLevels
- * {Integer}
- */
- numZoomLevels: null,
-
- /**
- * APIProperty: minScale
- * {Float}
- */
- minScale: null,
-
- /**
- * APIProperty: maxScale
- * {Float}
- */
- maxScale: null,
- /**
- * APIProperty: displayOutsideMaxExtent
- * {Boolean} Request map tiles that are completely outside of the max
- * extent for this layer. Defaults to false.
- */
- displayOutsideMaxExtent: false,
- /**
- * APIProperty: wrapDateLine
- * {Boolean} Wraps the world at the international dateline, so the map can
- * be panned infinitely in longitudinal direction. Only use this on the
- * base layer, and only if the layer's maxExtent equals the world bounds.
- * #487 for more info.
- */
- wrapDateLine: false,
-
- /**
- * Property: metadata
- * {Object} This object can be used to store additional information on a
- * layer object.
- */
- metadata: null,
-
- /**
- * Constructor: OpenLayers.Layer
- *
- * Parameters:
- * name - {String} The layer name
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- this.metadata = {};
-
- this.addOptions(options);
- this.name = name;
-
- if (this.id == null) {
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- this.div = OpenLayers.Util.createDiv(this.id);
- this.div.style.width = "100%";
- this.div.style.height = "100%";
- this.div.dir = "ltr";
- this.events = new OpenLayers.Events(this, this.div);
- if(this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
- }
- }
- },
-
- /**
- * Method: destroy
- * Destroy is a destructor: this is to alleviate cyclic references which
- * the Javascript garbage cleaner can not take care of on its own.
- *
- * Parameters:
- * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
- * been destroyed. Default is true.
- */
- destroy: function(setNewBaseLayer) {
- if (setNewBaseLayer == null) {
- setNewBaseLayer = true;
- }
- if (this.map != null) {
- this.map.removeLayer(this, setNewBaseLayer);
- }
- this.projection = null;
- this.map = null;
- this.name = null;
- this.div = null;
- this.options = null;
- if (this.events) {
- if(this.eventListeners) {
- this.events.un(this.eventListeners);
- }
- this.events.destroy();
- }
- this.eventListeners = null;
- this.events = null;
- },
-
- /**
- * Method: clone
- *
- * Parameters:
- * obj - {<OpenLayers.Layer>} The layer to be cloned
- *
- * Returns:
- * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer(this.name, this.getOptions());
- }
-
- // catch any randomly tagged-on properties
- OpenLayers.Util.applyDefaults(obj, this);
-
- // a cloned layer should never have its map property set
- // because it has not been added to a map yet.
- obj.map = null;
-
- return obj;
- },
-
- /**
- * Method: getOptions
- * Extracts an object from the layer with the properties that were set as
- * options, but updates them with the values currently set on the
- * instance.
- *
- * Returns:
- * {Object} the <options> of the layer, representing the current state.
- */
- getOptions: function() {
- var options = {};
- for(var o in this.options) {
- options[o] = this[o];
- }
- return options;
- },
-
- /**
- * APIMethod: setName
- * Sets the new layer name for this layer. Can trigger a changelayer event
- * on the map.
- *
- * Parameters:
- * newName - {String} The new name.
- */
- setName: function(newName) {
- if (newName != this.name) {
- this.name = newName;
- if (this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "name"
- });
- }
- }
- },
-
- /**
- * APIMethod: addOptions
- *
- * Parameters:
- * newOptions - {Object}
- * reinitialize - {Boolean} If set to true, and if resolution options of the
- * current baseLayer were changed, the map will be recentered to make
- * sure that it is displayed with a valid resolution, and a
- * changebaselayer event will be triggered.
- */
- addOptions: function (newOptions, reinitialize) {
- if (this.options == null) {
- this.options = {};
- }
-
- if (newOptions) {
- // make sure this.projection references a projection object
- if(typeof newOptions.projection == "string") {
- newOptions.projection = new OpenLayers.Projection(newOptions.projection);
- }
- if (newOptions.projection) {
- // get maxResolution, units and maxExtent from projection defaults if
- // they are not defined already
- OpenLayers.Util.applyDefaults(newOptions,
- OpenLayers.Projection.defaults[newOptions.projection.getCode()]);
- }
- // allow array for extents
- if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {
- newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);
- }
- if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) {
- newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent);
- }
- }
- // update our copy for clone
- OpenLayers.Util.extend(this.options, newOptions);
- // add new options to this
- OpenLayers.Util.extend(this, newOptions);
-
- // get the units from the projection, if we have a projection
- // and it it has units
- if(this.projection && this.projection.getUnits()) {
- this.units = this.projection.getUnits();
- }
- // re-initialize resolutions if necessary, i.e. if any of the
- // properties of the "properties" array defined below is set
- // in the new options
- if(this.map) {
- // store current resolution so we can try to restore it later
- var resolution = this.map.getResolution();
- var properties = this.RESOLUTION_PROPERTIES.concat(
- ["projection", "units", "minExtent", "maxExtent"]
- );
- for(var o in newOptions) {
- if(newOptions.hasOwnProperty(o) &&
- OpenLayers.Util.indexOf(properties, o) >= 0) {
- this.initResolutions();
- if (reinitialize && this.map.baseLayer === this) {
- // update map position, and restore previous resolution
- this.map.setCenter(this.map.getCenter(),
- this.map.getZoomForResolution(resolution),
- false, true
- );
- // trigger a changebaselayer event to make sure that
- // all controls (especially
- // OpenLayers.Control.PanZoomBar) get notified of the
- // new options
- this.map.events.triggerEvent("changebaselayer", {
- layer: this
- });
- }
- break;
- }
- }
- }
- },
- /**
- * APIMethod: onMapResize
- * This function can be implemented by subclasses
- */
- onMapResize: function() {
- //this function can be implemented by subclasses
- },
- /**
- * APIMethod: redraw
- * Redraws the layer. Returns true if the layer was redrawn, false if not.
- *
- * Returns:
- * {Boolean} The layer was redrawn.
- */
- redraw: function() {
- var redrawn = false;
- if (this.map) {
- // min/max Range may have changed
- this.inRange = this.calculateInRange();
- // map's center might not yet be set
- var extent = this.getExtent();
- if (extent && this.inRange && this.visibility) {
- var zoomChanged = true;
- this.moveTo(extent, zoomChanged, false);
- this.events.triggerEvent("moveend",
- {"zoomChanged": zoomChanged});
- redrawn = true;
- }
- }
- return redrawn;
- },
- /**
- * Method: moveTo
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
- * do some init work in that case.
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
- var display = this.visibility;
- if (!this.isBaseLayer) {
- display = display && this.inRange;
- }
- this.display(display);
- },
- /**
- * Method: moveByPx
- * Move the layer based on pixel vector. To be implemented by subclasses.
- *
- * Parameters:
- * dx - {Number} The x coord of the displacement vector.
- * dy - {Number} The y coord of the displacement vector.
- */
- moveByPx: function(dx, dy) {
- },
- /**
- * Method: setMap
- * Set the map property for the layer. This is done through an accessor
- * so that subclasses can override this and take special action once
- * they have their map variable set.
- *
- * Here we take care to bring over any of the necessary default
- * properties from the map.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- if (this.map == null) {
-
- this.map = map;
-
- // grab some essential layer data from the map if it hasn't already
- // been set
- this.maxExtent = this.maxExtent || this.map.maxExtent;
- this.minExtent = this.minExtent || this.map.minExtent;
- this.projection = this.projection || this.map.projection;
- if (typeof this.projection == "string") {
- this.projection = new OpenLayers.Projection(this.projection);
- }
- // Check the projection to see if we can get units -- if not, refer
- // to properties.
- this.units = this.projection.getUnits() ||
- this.units || this.map.units;
-
- this.initResolutions();
-
- if (!this.isBaseLayer) {
- this.inRange = this.calculateInRange();
- var show = ((this.visibility) && (this.inRange));
- this.div.style.display = show ? "" : "none";
- }
-
- // deal with gutters
- this.setTileSize();
- }
- },
-
- /**
- * Method: afterAdd
- * Called at the end of the map.addLayer sequence. At this point, the map
- * will have a base layer. To be overridden by subclasses.
- */
- afterAdd: function() {
- },
-
- /**
- * APIMethod: removeMap
- * Just as setMap() allows each layer the possibility to take a
- * personalized action on being added to the map, removeMap() allows
- * each layer to take a personalized action on being removed from it.
- * For now, this will be mostly unused, except for the EventPane layer,
- * which needs this hook so that it can remove the special invisible
- * pane.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- //to be overridden by subclasses
- },
-
- /**
- * APIMethod: getImageSize
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} optional tile bounds, can be used
- * by subclasses that have to deal with different tile sizes at the
- * layer extent edges (e.g. Zoomify)
- *
- * Returns:
- * {<OpenLayers.Size>} The size that the image should be, taking into
- * account gutters.
- */
- getImageSize: function(bounds) {
- return (this.imageSize || this.tileSize);
- },
-
- /**
- * APIMethod: setTileSize
- * Set the tile size based on the map size. This also sets layer.imageSize
- * or use by Tile.Image.
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setTileSize: function(size) {
- var tileSize = (size) ? size :
- ((this.tileSize) ? this.tileSize :
- this.map.getTileSize());
- this.tileSize = tileSize;
- if(this.gutter) {
- // layers with gutters need non-null tile sizes
- //if(tileSize == null) {
- // OpenLayers.console.error("Error in layer.setMap() for " +
- // this.name + ": layers with " +
- // "gutters need non-null tile sizes");
- //}
- this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter),
- tileSize.h + (2*this.gutter));
- }
- },
- /**
- * APIMethod: getVisibility
- *
- * Returns:
- * {Boolean} The layer should be displayed (if in range).
- */
- getVisibility: function() {
- return this.visibility;
- },
- /**
- * APIMethod: setVisibility
- * Set the visibility flag for the layer and hide/show & redraw
- * accordingly. Fire event unless otherwise specified
- *
- * Note that visibility is no longer simply whether or not the layer's
- * style.display is set to "block". Now we store a 'visibility' state
- * property on the layer class, this allows us to remember whether or
- * not we *desire* for a layer to be visible. In the case where the
- * map's resolution is out of the layer's range, this desire may be
- * subverted.
- *
- * Parameters:
- * visibility - {Boolean} Whether or not to display the layer (if in range)
- */
- setVisibility: function(visibility) {
- if (visibility != this.visibility) {
- this.visibility = visibility;
- this.display(visibility);
- this.redraw();
- if (this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "visibility"
- });
- }
- this.events.triggerEvent("visibilitychanged");
- }
- },
- /**
- * APIMethod: display
- * Hide or show the Layer. This is designed to be used internally, and
- * is not generally the way to enable or disable the layer. For that,
- * use the setVisibility function instead..
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- if (display != (this.div.style.display != "none")) {
- this.div.style.display = (display && this.calculateInRange()) ? "block" : "none";
- }
- },
- /**
- * APIMethod: calculateInRange
- *
- * Returns:
- * {Boolean} The layer is displayable at the current map's current
- * resolution. Note that if 'alwaysInRange' is true for the layer,
- * this function will always return true.
- */
- calculateInRange: function() {
- var inRange = false;
- if (this.alwaysInRange) {
- inRange = true;
- } else {
- if (this.map) {
- var resolution = this.map.getResolution();
- inRange = ( (resolution >= this.minResolution) &&
- (resolution <= this.maxResolution) );
- }
- }
- return inRange;
- },
- /**
- * APIMethod: setIsBaseLayer
- *
- * Parameters:
- * isBaseLayer - {Boolean}
- */
- setIsBaseLayer: function(isBaseLayer) {
- if (isBaseLayer != this.isBaseLayer) {
- this.isBaseLayer = isBaseLayer;
- if (this.map != null) {
- this.map.events.triggerEvent("changebaselayer", {
- layer: this
- });
- }
- }
- },
- /********************************************************/
- /* */
- /* Baselayer Functions */
- /* */
- /********************************************************/
-
- /**
- * Method: initResolutions
- * This method's responsibility is to set up the 'resolutions' array
- * for the layer -- this array is what the layer will use to interface
- * between the zoom levels of the map and the resolution display
- * of the layer.
- *
- * The user has several options that determine how the array is set up.
- *
- * For a detailed explanation, see the following wiki from the
- * openlayers.org homepage:
- * http://trac.openlayers.org/wiki/SettingZoomLevels
- */
- initResolutions: function() {
- // ok we want resolutions, here's our strategy:
- //
- // 1. if resolutions are defined in the layer config, use them
- // 2. else, if scales are defined in the layer config then derive
- // resolutions from these scales
- // 3. else, attempt to calculate resolutions from maxResolution,
- // minResolution, numZoomLevels, maxZoomLevel set in the
- // layer config
- // 4. if we still don't have resolutions, and if resolutions
- // are defined in the same, use them
- // 5. else, if scales are defined in the map then derive
- // resolutions from these scales
- // 6. else, attempt to calculate resolutions from maxResolution,
- // minResolution, numZoomLevels, maxZoomLevel set in the
- // map
- // 7. hope for the best!
- var i, len, p;
- var props = {}, alwaysInRange = true;
- // get resolution data from layer config
- // (we also set alwaysInRange in the layer as appropriate)
- for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
- p = this.RESOLUTION_PROPERTIES[i];
- props[p] = this.options[p];
- if(alwaysInRange && this.options[p]) {
- alwaysInRange = false;
- }
- }
- if(this.alwaysInRange == null) {
- this.alwaysInRange = alwaysInRange;
- }
- // if we don't have resolutions then attempt to derive them from scales
- if(props.resolutions == null) {
- props.resolutions = this.resolutionsFromScales(props.scales);
- }
- // if we still don't have resolutions then attempt to calculate them
- if(props.resolutions == null) {
- props.resolutions = this.calculateResolutions(props);
- }
- // if we couldn't calculate resolutions then we look at we have
- // in the map
- if(props.resolutions == null) {
- for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
- p = this.RESOLUTION_PROPERTIES[i];
- props[p] = this.options[p] != null ?
- this.options[p] : this.map[p];
- }
- if(props.resolutions == null) {
- props.resolutions = this.resolutionsFromScales(props.scales);
- }
- if(props.resolutions == null) {
- props.resolutions = this.calculateResolutions(props);
- }
- }
- // ok, we new need to set properties in the instance
- // get maxResolution from the config if it's defined there
- var maxResolution;
- if(this.options.maxResolution &&
- this.options.maxResolution !== "auto") {
- maxResolution = this.options.maxResolution;
- }
- if(this.options.minScale) {
- maxResolution = OpenLayers.Util.getResolutionFromScale(
- this.options.minScale, this.units);
- }
- // get minResolution from the config if it's defined there
- var minResolution;
- if(this.options.minResolution &&
- this.options.minResolution !== "auto") {
- minResolution = this.options.minResolution;
- }
- if(this.options.maxScale) {
- minResolution = OpenLayers.Util.getResolutionFromScale(
- this.options.maxScale, this.units);
- }
- if(props.resolutions) {
- //sort resolutions array descendingly
- props.resolutions.sort(function(a, b) {
- return (b - a);
- });
- // if we still don't have a maxResolution get it from the
- // resolutions array
- if(!maxResolution) {
- maxResolution = props.resolutions[0];
- }
- // if we still don't have a minResolution get it from the
- // resolutions array
- if(!minResolution) {
- var lastIdx = props.resolutions.length - 1;
- minResolution = props.resolutions[lastIdx];
- }
- }
- this.resolutions = props.resolutions;
- if(this.resolutions) {
- len = this.resolutions.length;
- this.scales = new Array(len);
- for(i=0; i<len; i++) {
- this.scales[i] = OpenLayers.Util.getScaleFromResolution(
- this.resolutions[i], this.units);
- }
- this.numZoomLevels = len;
- }
- this.minResolution = minResolution;
- if(minResolution) {
- this.maxScale = OpenLayers.Util.getScaleFromResolution(
- minResolution, this.units);
- }
- this.maxResolution = maxResolution;
- if(maxResolution) {
- this.minScale = OpenLayers.Util.getScaleFromResolution(
- maxResolution, this.units);
- }
- },
- /**
- * Method: resolutionsFromScales
- * Derive resolutions from scales.
- *
- * Parameters:
- * scales - {Array(Number)} Scales
- *
- * Returns
- * {Array(Number)} Resolutions
- */
- resolutionsFromScales: function(scales) {
- if(scales == null) {
- return;
- }
- var resolutions, i, len;
- len = scales.length;
- resolutions = new Array(len);
- for(i=0; i<len; i++) {
- resolutions[i] = OpenLayers.Util.getResolutionFromScale(
- scales[i], this.units);
- }
- return resolutions;
- },
- /**
- * Method: calculateResolutions
- * Calculate resolutions based on the provided properties.
- *
- * Parameters:
- * props - {Object} Properties
- *
- * Returns:
- * {Array({Number})} Array of resolutions.
- */
- calculateResolutions: function(props) {
- var viewSize, wRes, hRes;
- // determine maxResolution
- var maxResolution = props.maxResolution;
- if(props.minScale != null) {
- maxResolution =
- OpenLayers.Util.getResolutionFromScale(props.minScale,
- this.units);
- } else if(maxResolution == "auto" && this.maxExtent != null) {
- viewSize = this.map.getSize();
- wRes = this.maxExtent.getWidth() / viewSize.w;
- hRes = this.maxExtent.getHeight() / viewSize.h;
- maxResolution = Math.max(wRes, hRes);
- }
- // determine minResolution
- var minResolution = props.minResolution;
- if(props.maxScale != null) {
- minResolution =
- OpenLayers.Util.getResolutionFromScale(props.maxScale,
- this.units);
- } else if(props.minResolution == "auto" && this.minExtent != null) {
- viewSize = this.map.getSize();
- wRes = this.minExtent.getWidth() / viewSize.w;
- hRes = this.minExtent.getHeight()/ viewSize.h;
- minResolution = Math.max(wRes, hRes);
- }
- if(typeof maxResolution !== "number" &&
- typeof minResolution !== "number" &&
- this.maxExtent != null) {
- // maxResolution for default grid sets assumes that at zoom
- // level zero, the whole world fits on one tile.
- var tileSize = this.map.getTileSize();
- maxResolution = Math.max(
- this.maxExtent.getWidth() / tileSize.w,
- this.maxExtent.getHeight() / tileSize.h
- );
- }
- // determine numZoomLevels
- var maxZoomLevel = props.maxZoomLevel;
- var numZoomLevels = props.numZoomLevels;
- if(typeof minResolution === "number" &&
- typeof maxResolution === "number" && numZoomLevels === undefined) {
- var ratio = maxResolution / minResolution;
- numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;
- } else if(numZoomLevels === undefined && maxZoomLevel != null) {
- numZoomLevels = maxZoomLevel + 1;
- }
- // are we able to calculate resolutions?
- if(typeof numZoomLevels !== "number" || numZoomLevels <= 0 ||
- (typeof maxResolution !== "number" &&
- typeof minResolution !== "number")) {
- return;
- }
- // now we have numZoomLevels and at least one of maxResolution
- // or minResolution, we can populate the resolutions array
- var resolutions = new Array(numZoomLevels);
- var base = 2;
- if(typeof minResolution == "number" &&
- typeof maxResolution == "number") {
- // if maxResolution and minResolution are set, we calculate
- // the base for exponential scaling that starts at
- // maxResolution and ends at minResolution in numZoomLevels
- // steps.
- base = Math.pow(
- (maxResolution / minResolution),
- (1 / (numZoomLevels - 1))
- );
- }
- var i;
- if(typeof maxResolution === "number") {
- for(i=0; i<numZoomLevels; i++) {
- resolutions[i] = maxResolution / Math.pow(base, i);
- }
- } else {
- for(i=0; i<numZoomLevels; i++) {
- resolutions[numZoomLevels - 1 - i] =
- minResolution * Math.pow(base, i);
- }
- }
- return resolutions;
- },
- /**
- * APIMethod: getResolution
- *
- * Returns:
- * {Float} The currently selected resolution of the map, taken from the
- * resolutions array, indexed by current zoom level.
- */
- getResolution: function() {
- var zoom = this.map.getZoom();
- return this.getResolutionForZoom(zoom);
- },
- /**
- * APIMethod: getExtent
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
- * bounds of the current viewPort.
- */
- getExtent: function() {
- // just use stock map calculateBounds function -- passing no arguments
- // means it will user map's current center & resolution
- //
- return this.map.calculateBounds();
- },
- /**
- * APIMethod: getZoomForExtent
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * closest - {Boolean} Find the zoom level that most closely fits the
- * specified bounds. Note that this may result in a zoom that does
- * not exactly contain the entire extent.
- * Default is false.
- *
- * Returns:
- * {Integer} The index of the zoomLevel (entry in the resolutions array)
- * for the passed-in extent. We do this by calculating the ideal
- * resolution for the given extent (based on the map size) and then
- * calling getZoomForResolution(), passing along the 'closest'
- * parameter.
- */
- getZoomForExtent: function(extent, closest) {
- var viewSize = this.map.getSize();
- var idealResolution = Math.max( extent.getWidth() / viewSize.w,
- extent.getHeight() / viewSize.h );
- return this.getZoomForResolution(idealResolution, closest);
- },
-
- /**
- * Method: getDataExtent
- * Calculates the max extent which includes all of the data for the layer.
- * This function is to be implemented by subclasses.
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getDataExtent: function () {
- //to be implemented by subclasses
- },
- /**
- * APIMethod: getResolutionForZoom
- *
- * Parameters:
- * zoom - {Float}
- *
- * Returns:
- * {Float} A suitable resolution for the specified zoom.
- */
- getResolutionForZoom: function(zoom) {
- zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
- var resolution;
- if(this.map.fractionalZoom) {
- var low = Math.floor(zoom);
- var high = Math.ceil(zoom);
- resolution = this.resolutions[low] -
- ((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
- } else {
- resolution = this.resolutions[Math.round(zoom)];
- }
- return resolution;
- },
- /**
- * APIMethod: getZoomForResolution
- *
- * Parameters:
- * resolution - {Float}
- * closest - {Boolean} Find the zoom level that corresponds to the absolute
- * closest resolution, which may result in a zoom whose corresponding
- * resolution is actually smaller than we would have desired (if this
- * is being called from a getZoomForExtent() call, then this means that
- * the returned zoom index might not actually contain the entire
- * extent specified... but it'll be close).
- * Default is false.
- *
- * Returns:
- * {Integer} The index of the zoomLevel (entry in the resolutions array)
- * that corresponds to the best fit resolution given the passed in
- * value and the 'closest' specification.
- */
- getZoomForResolution: function(resolution, closest) {
- var zoom, i, len;
- if(this.map.fractionalZoom) {
- var lowZoom = 0;
- var highZoom = this.resolutions.length - 1;
- var highRes = this.resolutions[lowZoom];
- var lowRes = this.resolutions[highZoom];
- var res;
- for(i=0, len=this.resolutions.length; i<len; ++i) {
- res = this.resolutions[i];
- if(res >= resolution) {
- highRes = res;
- lowZoom = i;
- }
- if(res <= resolution) {
- lowRes = res;
- highZoom = i;
- break;
- }
- }
- var dRes = highRes - lowRes;
- if(dRes > 0) {
- zoom = lowZoom + ((highRes - resolution) / dRes);
- } else {
- zoom = lowZoom;
- }
- } else {
- var diff;
- var minDiff = Number.POSITIVE_INFINITY;
- for(i=0, len=this.resolutions.length; i<len; i++) {
- if (closest) {
- diff = Math.abs(this.resolutions[i] - resolution);
- if (diff > minDiff) {
- break;
- }
- minDiff = diff;
- } else {
- if (this.resolutions[i] < resolution) {
- break;
- }
- }
- }
- zoom = Math.max(0, i-1);
- }
- return zoom;
- },
-
- /**
- * APIMethod: getLonLatFromViewPortPx
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or
- * an object with a 'x'
- * and 'y' properties.
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
- * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
- */
- getLonLatFromViewPortPx: function (viewPortPx) {
- var lonlat = null;
- var map = this.map;
- if (viewPortPx != null && map.minPx) {
- var res = map.getResolution();
- var maxExtent = map.getMaxExtent({restricted: true});
- var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;
- var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;
- lonlat = new OpenLayers.LonLat(lon, lat);
- if (this.wrapDateLine) {
- lonlat = lonlat.wrapDateLine(this.maxExtent);
- }
- }
- return lonlat;
- },
- /**
- * APIMethod: getViewPortPxFromLonLat
- * Returns a pixel location given a map location. This method will return
- * fractional pixel values.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>|Object} An OpenLayers.LonLat or
- * an object with a 'lon'
- * and 'lat' properties.
- *
- * Returns:
- * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
- * lonlat translated into view port pixels.
- */
- getViewPortPxFromLonLat: function (lonlat, resolution) {
- var px = null;
- if (lonlat != null) {
- resolution = resolution || this.map.getResolution();
- var extent = this.map.calculateBounds(null, resolution);
- px = new OpenLayers.Pixel(
- (1/resolution * (lonlat.lon - extent.left)),
- (1/resolution * (extent.top - lonlat.lat))
- );
- }
- return px;
- },
-
- /**
- * APIMethod: setOpacity
- * Sets the opacity for the entire layer (all images)
- *
- * Parameters:
- * opacity - {Float}
- */
- setOpacity: function(opacity) {
- if (opacity != this.opacity) {
- this.opacity = opacity;
- var childNodes = this.div.childNodes;
- for(var i = 0, len = childNodes.length; i < len; ++i) {
- var element = childNodes[i].firstChild || childNodes[i];
- var lastChild = childNodes[i].lastChild;
- //TODO de-uglify this
- if (lastChild && lastChild.nodeName.toLowerCase() === "iframe") {
- element = lastChild.parentNode;
- }
- OpenLayers.Util.modifyDOMElement(element, null, null, null,
- null, null, null, opacity);
- }
- if (this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "opacity"
- });
- }
- }
- },
- /**
- * Method: getZIndex
- *
- * Returns:
- * {Integer} the z-index of this layer
- */
- getZIndex: function () {
- return this.div.style.zIndex;
- },
- /**
- * Method: setZIndex
- *
- * Parameters:
- * zIndex - {Integer}
- */
- setZIndex: function (zIndex) {
- this.div.style.zIndex = zIndex;
- },
- /**
- * Method: adjustBounds
- * This function will take a bounds, and if wrapDateLine option is set
- * on the layer, it will return a bounds which is wrapped around the
- * world. We do not wrap for bounds which *cross* the
- * maxExtent.left/right, only bounds which are entirely to the left
- * or entirely to the right.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- adjustBounds: function (bounds) {
- if (this.gutter) {
- // Adjust the extent of a bounds in map units by the
- // layer's gutter in pixels.
- var mapGutter = this.gutter * this.map.getResolution();
- bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
- bounds.bottom - mapGutter,
- bounds.right + mapGutter,
- bounds.top + mapGutter);
- }
- if (this.wrapDateLine) {
- // wrap around the date line, within the limits of rounding error
- var wrappingOptions = {
- 'rightTolerance':this.getResolution(),
- 'leftTolerance':this.getResolution()
- };
- bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
-
- }
- return bounds;
- },
- CLASS_NAME: "OpenLayers.Layer"
- });
- /* ======================================================================
- OpenLayers/Layer/SphericalMercator.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Layer.js
- * @requires OpenLayers/Projection.js
- */
- /**
- * Class: OpenLayers.Layer.SphericalMercator
- * A mixin for layers that wraps up the pieces neccesary to have a coordinate
- * conversion for working with commercial APIs which use a spherical
- * mercator projection. Using this layer as a base layer, additional
- * layers can be used as overlays if they are in the same projection.
- *
- * A layer is given properties of this object by setting the sphericalMercator
- * property to true.
- *
- * More projection information:
- * - http://spatialreference.org/ref/user/google-projection/
- *
- * Proj4 Text:
- * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
- * +k=1.0 +units=m +nadgrids=@null +no_defs
- *
- * WKT:
- * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
- * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]],
- * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295],
- * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
- * PROJECTION["Mercator_1SP_Google"],
- * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0],
- * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0],
- * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
- * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
- */
- OpenLayers.Layer.SphericalMercator = {
- /**
- * Method: getExtent
- * Get the map's extent.
- *
- * Returns:
- * {<OpenLayers.Bounds>} The map extent.
- */
- getExtent: function() {
- var extent = null;
- if (this.sphericalMercator) {
- extent = this.map.calculateBounds();
- } else {
- extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
- }
- return extent;
- },
- /**
- * Method: getLonLatFromViewPortPx
- * Get a map location from a pixel location
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
- * port OpenLayers.Pixel, translated into lon/lat by map lib
- * If the map lib is not loaded or not centered, returns null
- */
- getLonLatFromViewPortPx: function (viewPortPx) {
- return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
- },
-
- /**
- * Method: getViewPortPxFromLonLat
- * Get a pixel location from a map location
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * OpenLayers.LonLat, translated into view port pixels by map lib
- * If map lib is not loaded or not centered, returns null
- */
- getViewPortPxFromLonLat: function (lonlat) {
- return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
- },
- /**
- * Method: initMercatorParameters
- * Set up the mercator parameters on the layer: resolutions,
- * projection, units.
- */
- initMercatorParameters: function() {
- // set up properties for Mercator - assume EPSG:900913
- this.RESOLUTIONS = [];
- var maxResolution = 156543.03390625;
- for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
- this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
- }
- this.units = "m";
- this.projection = this.projection || "EPSG:900913";
- },
- /**
- * APIMethod: forwardMercator
- * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
- *
- * Parameters:
- * lon - {float}
- * lat - {float}
- *
- * Returns:
- * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
- */
- forwardMercator: (function() {
- var gg = new OpenLayers.Projection("EPSG:4326");
- var sm = new OpenLayers.Projection("EPSG:900913");
- return function(lon, lat) {
- var point = OpenLayers.Projection.transform({x: lon, y: lat}, gg, sm);
- return new OpenLayers.LonLat(point.x, point.y);
- };
- })(),
- /**
- * APIMethod: inverseMercator
- * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
- *
- * Parameters:
- * x - {float} A map x in Spherical Mercator.
- * y - {float} A map y in Spherical Mercator.
- *
- * Returns:
- * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
- */
- inverseMercator: (function() {
- var gg = new OpenLayers.Projection("EPSG:4326");
- var sm = new OpenLayers.Projection("EPSG:900913");
- return function(x, y) {
- var point = OpenLayers.Projection.transform({x: x, y: y}, sm, gg);
- return new OpenLayers.LonLat(point.x, point.y);
- };
- })()
- };
- /* ======================================================================
- OpenLayers/Layer/EventPane.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Layer.js
- * @requires OpenLayers/Util.js
- */
- /**
- * Class: OpenLayers.Layer.EventPane
- * Base class for 3rd party layers, providing a DOM element which isolates
- * the 3rd-party layer from mouse events.
- * Only used by Google layers.
- *
- * Automatically instantiated by the Google constructor, and not usually instantiated directly.
- *
- * Create a new event pane layer with the
- * <OpenLayers.Layer.EventPane> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
- OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * APIProperty: smoothDragPan
- * {Boolean} smoothDragPan determines whether non-public/internal API
- * methods are used for better performance while dragging EventPane
- * layers. When not in sphericalMercator mode, the smoother dragging
- * doesn't actually move north/south directly with the number of
- * pixels moved, resulting in a slight offset when you drag your mouse
- * north south with this option on. If this visual disparity bothers
- * you, you should turn this option off, or use spherical mercator.
- * Default is on.
- */
- smoothDragPan: true,
- /**
- * Property: isBaseLayer
- * {Boolean} EventPaned layers are always base layers, by necessity.
- */
- isBaseLayer: true,
- /**
- * APIProperty: isFixed
- * {Boolean} EventPaned layers are fixed by default.
- */
- isFixed: true,
- /**
- * Property: pane
- * {DOMElement} A reference to the element that controls the events.
- */
- pane: null,
- /**
- * Property: mapObject
- * {Object} This is the object which will be used to load the 3rd party library
- * in the case of the google layer, this will be of type GMap,
- * in the case of the ve layer, this will be of type VEMap
- */
- mapObject: null,
- /**
- * Constructor: OpenLayers.Layer.EventPane
- * Create a new event pane layer
- *
- * Parameters:
- * name - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
- if (this.pane == null) {
- this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane");
- }
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct this layer.
- */
- destroy: function() {
- this.mapObject = null;
- this.pane = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setMap
- * Set the map property for the layer. This is done through an accessor
- * so that subclasses can override this and take special action once
- * they have their map variable set.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.prototype.setMap.apply(this, arguments);
-
- this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
- this.pane.style.display = this.div.style.display;
- this.pane.style.width="100%";
- this.pane.style.height="100%";
- if (OpenLayers.BROWSER_NAME == "msie") {
- this.pane.style.background =
- "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")";
- }
- if (this.isFixed) {
- this.map.viewPortDiv.appendChild(this.pane);
- } else {
- this.map.layerContainerDiv.appendChild(this.pane);
- }
- // once our layer has been added to the map, we can load it
- this.loadMapObject();
-
- // if map didn't load, display warning
- if (this.mapObject == null) {
- this.loadWarningMessage();
- }
- },
- /**
- * APIMethod: removeMap
- * On being removed from the map, we'll like to remove the invisible 'pane'
- * div that we added to it on creation.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- if (this.pane && this.pane.parentNode) {
- this.pane.parentNode.removeChild(this.pane);
- }
- OpenLayers.Layer.prototype.removeMap.apply(this, arguments);
- },
-
- /**
- * Method: loadWarningMessage
- * If we can't load the map lib, then display an error message to the
- * user and tell them where to go for help.
- *
- * This function sets up the layout for the warning message. Each 3rd
- * party layer must implement its own getWarningHTML() function to
- * provide the actual warning message.
- */
- loadWarningMessage:function() {
- this.div.style.backgroundColor = "darkblue";
- var viewSize = this.map.getSize();
-
- var msgW = Math.min(viewSize.w, 300);
- var msgH = Math.min(viewSize.h, 200);
- var size = new OpenLayers.Size(msgW, msgH);
- var centerPx = new OpenLayers.Pixel(viewSize.w/2, viewSize.h/2);
- var topLeft = centerPx.add(-size.w/2, -size.h/2);
- var div = OpenLayers.Util.createDiv(this.name + "_warning",
- topLeft,
- size,
- null,
- null,
- null,
- "auto");
- div.style.padding = "7px";
- div.style.backgroundColor = "yellow";
- div.innerHTML = this.getWarningHTML();
- this.div.appendChild(div);
- },
-
- /**
- * Method: getWarningHTML
- * To be implemented by subclasses.
- *
- * Returns:
- * {String} String with information on why layer is broken, how to get
- * it working.
- */
- getWarningHTML:function() {
- //should be implemented by subclasses
- return "";
- },
-
- /**
- * Method: display
- * Set the display on the pane
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- OpenLayers.Layer.prototype.display.apply(this, arguments);
- this.pane.style.display = this.div.style.display;
- },
-
- /**
- * Method: setZIndex
- * Set the z-index order for the pane.
- *
- * Parameters:
- * zIndex - {int}
- */
- setZIndex: function (zIndex) {
- OpenLayers.Layer.prototype.setZIndex.apply(this, arguments);
- this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
- },
-
- /**
- * Method: moveByPx
- * Move the layer based on pixel vector. To be implemented by subclasses.
- *
- * Parameters:
- * dx - {Number} The x coord of the displacement vector.
- * dy - {Number} The y coord of the displacement vector.
- */
- moveByPx: function(dx, dy) {
- OpenLayers.Layer.prototype.moveByPx.apply(this, arguments);
-
- if (this.dragPanMapObject) {
- this.dragPanMapObject(dx, -dy);
- } else {
- this.moveTo(this.map.getCachedCenter());
- }
- },
- /**
- * Method: moveTo
- * Handle calls to move the layer.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
- if (this.mapObject != null) {
- var newCenter = this.map.getCenter();
- var newZoom = this.map.getZoom();
- if (newCenter != null) {
- var moOldCenter = this.getMapObjectCenter();
- var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter);
- var moOldZoom = this.getMapObjectZoom();
- var oldZoom= this.getOLZoomFromMapObjectZoom(moOldZoom);
- if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) {
- if (!zoomChanged && oldCenter && this.dragPanMapObject &&
- this.smoothDragPan) {
- var oldPx = this.map.getViewPortPxFromLonLat(oldCenter);
- var newPx = this.map.getViewPortPxFromLonLat(newCenter);
- this.dragPanMapObject(newPx.x-oldPx.x, oldPx.y-newPx.y);
- } else {
- var center = this.getMapObjectLonLatFromOLLonLat(newCenter);
- var zoom = this.getMapObjectZoomFromOLZoom(newZoom);
- this.setMapObjectCenter(center, zoom, dragging);
- }
- }
- }
- }
- },
- /********************************************************/
- /* */
- /* Baselayer Functions */
- /* */
- /********************************************************/
- /**
- * Method: getLonLatFromViewPortPx
- * Get a map location from a pixel location
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
- * port OpenLayers.Pixel, translated into lon/lat by map lib
- * If the map lib is not loaded or not centered, returns null
- */
- getLonLatFromViewPortPx: function (viewPortPx) {
- var lonlat = null;
- if ( (this.mapObject != null) &&
- (this.getMapObjectCenter() != null) ) {
- var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx);
- var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel);
- lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat);
- }
- return lonlat;
- },
-
- /**
- * Method: getViewPortPxFromLonLat
- * Get a pixel location from a map location
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
- * OpenLayers.LonLat, translated into view port pixels by map lib
- * If map lib is not loaded or not centered, returns null
- */
- getViewPortPxFromLonLat: function (lonlat) {
- var viewPortPx = null;
- if ( (this.mapObject != null) &&
- (this.getMapObjectCenter() != null) ) {
- var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat);
- var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat);
-
- viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel);
- }
- return viewPortPx;
- },
- /********************************************************/
- /* */
- /* Translation Functions */
- /* */
- /* The following functions translate Map Object and */
- /* OL formats for Pixel, LonLat */
- /* */
- /********************************************************/
- //
- // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat
- //
- /**
- * Method: getOLLonLatFromMapObjectLonLat
- * Get an OL style map location from a 3rd party style map location
- *
- * Parameters
- * moLonLat - {Object}
- *
- * Returns:
- * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in
- * MapObject LonLat
- * Returns null if null value is passed in
- */
- getOLLonLatFromMapObjectLonLat: function(moLonLat) {
- var olLonLat = null;
- if (moLonLat != null) {
- var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);
- var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);
- olLonLat = new OpenLayers.LonLat(lon, lat);
- }
- return olLonLat;
- },
- /**
- * Method: getMapObjectLonLatFromOLLonLat
- * Get a 3rd party map location from an OL map location.
- *
- * Parameters:
- * olLonLat - {<OpenLayers.LonLat>}
- *
- * Returns:
- * {Object} A MapObject LonLat, translated from the passed in
- * OpenLayers.LonLat
- * Returns null if null value is passed in
- */
- getMapObjectLonLatFromOLLonLat: function(olLonLat) {
- var moLatLng = null;
- if (olLonLat != null) {
- moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon,
- olLonLat.lat);
- }
- return moLatLng;
- },
- //
- // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel
- //
- /**
- * Method: getOLPixelFromMapObjectPixel
- * Get an OL pixel location from a 3rd party pixel location.
- *
- * Parameters:
- * moPixel - {Object}
- *
- * Returns:
- * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in
- * MapObject Pixel
- * Returns null if null value is passed in
- */
- getOLPixelFromMapObjectPixel: function(moPixel) {
- var olPixel = null;
- if (moPixel != null) {
- var x = this.getXFromMapObjectPixel(moPixel);
- var y = this.getYFromMapObjectPixel(moPixel);
- olPixel = new OpenLayers.Pixel(x, y);
- }
- return olPixel;
- },
- /**
- * Method: getMapObjectPixelFromOLPixel
- * Get a 3rd party pixel location from an OL pixel location
- *
- * Parameters:
- * olPixel - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {Object} A MapObject Pixel, translated from the passed in
- * OpenLayers.Pixel
- * Returns null if null value is passed in
- */
- getMapObjectPixelFromOLPixel: function(olPixel) {
- var moPixel = null;
- if (olPixel != null) {
- moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y);
- }
- return moPixel;
- },
- CLASS_NAME: "OpenLayers.Layer.EventPane"
- });
- /* ======================================================================
- OpenLayers/Layer/FixedZoomLevels.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Layer.js
- */
- /**
- * Class: OpenLayers.Layer.FixedZoomLevels
- * Some Layers will already have established zoom levels (like google
- * or ve). Instead of trying to determine them and populate a resolutions[]
- * Array with those values, we will hijack the resolution functionality
- * here.
- *
- * When you subclass FixedZoomLevels:
- *
- * The initResolutions() call gets nullified, meaning no resolutions[] array
- * is set up. Which would be a big problem getResolution() in Layer, since
- * it merely takes map.zoom and indexes into resolutions[]... but....
- *
- * The getResolution() call is also overridden. Instead of using the
- * resolutions[] array, we simply calculate the current resolution based
- * on the current extent and the current map size. But how will we be able
- * to calculate the current extent without knowing the resolution...?
- *
- * The getExtent() function is also overridden. Instead of calculating extent
- * based on the center point and the current resolution, we instead
- * calculate the extent by getting the lonlats at the top-left and
- * bottom-right by using the getLonLatFromViewPortPx() translation function,
- * taken from the pixel locations (0,0) and the size of the map. But how
- * will we be able to do lonlat-px translation without resolution....?
- *
- * The getZoomForResolution() method is overridden. Instead of indexing into
- * the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
- * the desired resolution. With this extent, we then call getZoomForExtent()
- *
- *
- * Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
- * it is your responsibility to provide the following three functions:
- *
- * - getLonLatFromViewPortPx
- * - getViewPortPxFromLonLat
- * - getZoomForExtent
- *
- * ...those three functions should generally be provided by any reasonable
- * API that you might be working from.
- *
- */
- OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
-
- /********************************************************/
- /* */
- /* Baselayer Functions */
- /* */
- /* The following functions must all be implemented */
- /* by all base layers */
- /* */
- /********************************************************/
-
- /**
- * Constructor: OpenLayers.Layer.FixedZoomLevels
- * Create a new fixed zoom levels layer.
- */
- initialize: function() {
- //this class is only just to add the following functions...
- // nothing to actually do here... but it is probably a good
- // idea to have layers that use these functions call this
- // inititalize() anyways, in case at some point we decide we
- // do want to put some functionality or state in here.
- },
-
- /**
- * Method: initResolutions
- * Populate the resolutions array
- */
- initResolutions: function() {
- var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels'];
-
- for(var i=0, len=props.length; i<len; i++) {
- var property = props[i];
- this[property] = (this.options[property] != null)
- ? this.options[property]
- : this.map[property];
- }
- if ( (this.minZoomLevel == null) ||
- (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
- this.minZoomLevel = this.MIN_ZOOM_LEVEL;
- }
- //
- // At this point, we know what the minimum desired zoom level is, and
- // we must calculate the total number of zoom levels.
- //
- // Because we allow for the setting of either the 'numZoomLevels'
- // or the 'maxZoomLevel' properties... on either the layer or the
- // map, we have to define some rules to see which we take into
- // account first in this calculation.
- //
- // The following is the precedence list for these properties:
- //
- // (1) numZoomLevels set on layer
- // (2) maxZoomLevel set on layer
- // (3) numZoomLevels set on map
- // (4) maxZoomLevel set on map*
- // (5) none of the above*
- //
- // *Note that options (4) and (5) are only possible if the user
- // _explicitly_ sets the 'numZoomLevels' property on the map to
- // null, since it is set by default to 16.
- //
- //
- // Note to future: In 3.0, I think we should remove the default
- // value of 16 for map.numZoomLevels. Rather, I think that value
- // should be set as a default on the Layer.WMS class. If someone
- // creates a 3rd party layer and does not specify any 'minZoomLevel',
- // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
- // specified any of those on the map object either.. then I think
- // it is fair to say that s/he wants all the zoom levels available.
- //
- // By making map.numZoomLevels *null* by default, that will be the
- // case. As it is, I don't feel comfortable changing that right now
- // as it would be a glaring API change and actually would probably
- // break many peoples' codes.
- //
- //the number of zoom levels we'd like to have.
- var desiredZoomLevels;
- //this is the maximum number of zoom levels the layer will allow,
- // given the specified starting minimum zoom level.
- var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
- if ( ((this.options.numZoomLevels == null) &&
- (this.options.maxZoomLevel != null)) // (2)
- ||
- ((this.numZoomLevels == null) &&
- (this.maxZoomLevel != null)) // (4)
- ) {
- //calculate based on specified maxZoomLevel (on layer or map)
- desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
- } else {
- //calculate based on specified numZoomLevels (on layer or map)
- // this covers cases (1) and (3)
- desiredZoomLevels = this.numZoomLevels;
- }
- if (desiredZoomLevels != null) {
- //Now that we know what we would *like* the number of zoom levels
- // to be, based on layer or map options, we have to make sure that
- // it does not conflict with the actual limit, as specified by
- // the constants on the layer itself (and calculated into the
- // 'limitZoomLevels' variable).
- this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
- } else {
- // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
- // set on either the layer or the map. So we just use the
- // maximum limit as calculated by the layer's constants.
- this.numZoomLevels = limitZoomLevels;
- }
- //now that the 'numZoomLevels' is appropriately, safely set,
- // we go back and re-calculate the 'maxZoomLevel'.
- this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
- if (this.RESOLUTIONS != null) {
- var resolutionsIndex = 0;
- this.resolutions = [];
- for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
- this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
- }
- this.maxResolution = this.resolutions[0];
- this.minResolution = this.resolutions[this.resolutions.length - 1];
- }
- },
-
- /**
- * APIMethod: getResolution
- * Get the current map resolution
- *
- * Returns:
- * {Float} Map units per Pixel
- */
- getResolution: function() {
- if (this.resolutions != null) {
- return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
- } else {
- var resolution = null;
-
- var viewSize = this.map.getSize();
- var extent = this.getExtent();
-
- if ((viewSize != null) && (extent != null)) {
- resolution = Math.max( extent.getWidth() / viewSize.w,
- extent.getHeight() / viewSize.h );
- }
- return resolution;
- }
- },
- /**
- * APIMethod: getExtent
- * Calculates using px-> lonlat translation functions on tl and br
- * corners of viewport
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
- * bounds of the current viewPort.
- */
- getExtent: function () {
- var size = this.map.getSize();
- var tl = this.getLonLatFromViewPortPx({
- x: 0, y: 0
- });
- var br = this.getLonLatFromViewPortPx({
- x: size.w, y: size.h
- });
-
- if ((tl != null) && (br != null)) {
- return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat);
- } else {
- return null;
- }
- },
- /**
- * Method: getZoomForResolution
- * Get the zoom level for a given resolution
- *
- * Parameters:
- * resolution - {Float}
- *
- * Returns:
- * {Integer} A suitable zoom level for the specified resolution.
- * If no baselayer is set, returns null.
- */
- getZoomForResolution: function(resolution) {
-
- if (this.resolutions != null) {
- return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
- } else {
- var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
- return this.getZoomForExtent(extent);
- }
- },
-
- /********************************************************/
- /* */
- /* Translation Functions */
- /* */
- /* The following functions translate GMaps and OL */
- /* formats for Pixel, LonLat, Bounds, and Zoom */
- /* */
- /********************************************************/
-
-
- //
- // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
- //
-
- /**
- * Method: getOLZoomFromMapObjectZoom
- * Get the OL zoom index from the map object zoom level
- *
- * Parameters:
- * moZoom - {Integer}
- *
- * Returns:
- * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
- * Returns null if null value is passed in
- */
- getOLZoomFromMapObjectZoom: function(moZoom) {
- var zoom = null;
- if (moZoom != null) {
- zoom = moZoom - this.minZoomLevel;
- if (this.map.baseLayer !== this) {
- zoom = this.map.baseLayer.getZoomForResolution(
- this.getResolutionForZoom(zoom)
- );
- }
- }
- return zoom;
- },
-
- /**
- * Method: getMapObjectZoomFromOLZoom
- * Get the map object zoom level from the OL zoom level
- *
- * Parameters:
- * olZoom - {Integer}
- *
- * Returns:
- * {Integer} A MapObject level, translated from the passed in olZoom
- * Returns null if null value is passed in
- */
- getMapObjectZoomFromOLZoom: function(olZoom) {
- var zoom = null;
- if (olZoom != null) {
- zoom = olZoom + this.minZoomLevel;
- if (this.map.baseLayer !== this) {
- zoom = this.getZoomForResolution(
- this.map.baseLayer.getResolutionForZoom(zoom)
- );
- }
- }
- return zoom;
- },
- CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
- });
- /* ======================================================================
- OpenLayers/Layer/Google.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Layer/SphericalMercator.js
- * @requires OpenLayers/Layer/EventPane.js
- * @requires OpenLayers/Layer/FixedZoomLevels.js
- * @requires OpenLayers/Lang.js
- */
- /**
- * Class: OpenLayers.Layer.Google
- *
- * Provides a wrapper for Google's Maps API
- * Normally the Terms of Use for this API do not allow wrapping, but Google
- * have provided written consent to OpenLayers for this - see email in
- * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html
- *
- * Inherits from:
- * - <OpenLayers.Layer.SphericalMercator>
- * - <OpenLayers.Layer.EventPane>
- * - <OpenLayers.Layer.FixedZoomLevels>
- */
- OpenLayers.Layer.Google = OpenLayers.Class(
- OpenLayers.Layer.EventPane,
- OpenLayers.Layer.FixedZoomLevels, {
-
- /**
- * Constant: MIN_ZOOM_LEVEL
- * {Integer} 0
- */
- MIN_ZOOM_LEVEL: 0,
-
- /**
- * Constant: MAX_ZOOM_LEVEL
- * {Integer} 21
- */
- MAX_ZOOM_LEVEL: 21,
- /**
- * Constant: RESOLUTIONS
- * {Array(Float)} Hardcode these resolutions so that they are more closely
- * tied with the standard wms projection
- */
- RESOLUTIONS: [
- 1.40625,
- 0.703125,
- 0.3515625,
- 0.17578125,
- 0.087890625,
- 0.0439453125,
- 0.02197265625,
- 0.010986328125,
- 0.0054931640625,
- 0.00274658203125,
- 0.001373291015625,
- 0.0006866455078125,
- 0.00034332275390625,
- 0.000171661376953125,
- 0.0000858306884765625,
- 0.00004291534423828125,
- 0.00002145767211914062,
- 0.00001072883605957031,
- 0.00000536441802978515,
- 0.00000268220901489257,
- 0.0000013411045074462891,
- 0.00000067055225372314453
- ],
- /**
- * APIProperty: type
- * {GMapType}
- */
- type: null,
- /**
- * APIProperty: wrapDateLine
- * {Boolean} Allow user to pan forever east/west. Default is true.
- * Setting this to false only restricts panning if
- * <sphericalMercator> is true.
- */
- wrapDateLine: true,
- /**
- * APIProperty: sphericalMercator
- * {Boolean} Should the map act as a mercator-projected map? This will
- * cause all interactions with the map to be in the actual map
- * projection, which allows support for vector drawing, overlaying
- * other maps, etc.
- */
- sphericalMercator: false,
-
- /**
- * Property: version
- * {Number} The version of the Google Maps API
- */
- version: null,
- /**
- * Constructor: OpenLayers.Layer.Google
- *
- * Parameters:
- * name - {String} A name for the layer.
- * options - {Object} An optional object whose properties will be set
- * on the layer.
- */
- initialize: function(name, options) {
- options = options || {};
- if(!options.version) {
- options.version = typeof GMap2 === "function" ? "2" : "3";
- }
- var mixin = OpenLayers.Layer.Google["v" +
- options.version.replace(/\./g, "_")];
- if (mixin) {
- OpenLayers.Util.applyDefaults(options, mixin);
- } else {
- throw "Unsupported Google Maps API version: " + options.version;
- }
- OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS);
- if (options.maxExtent) {
- options.maxExtent = options.maxExtent.clone();
- }
- OpenLayers.Layer.EventPane.prototype.initialize.apply(this,
- [name, options]);
- OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
- [name, options]);
- if (this.sphericalMercator) {
- OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
- this.initMercatorParameters();
- }
- },
- /**
- * Method: clone
- * Create a clone of this layer
- *
- * Returns:
- * {<OpenLayers.Layer.Google>} An exact clone of this layer
- */
- clone: function() {
- /**
- * This method isn't intended to be called by a subclass and it
- * doesn't call the same method on the superclass. We don't call
- * the super's clone because we don't want properties that are set
- * on this layer after initialize (i.e. this.mapObject etc.).
- */
- return new OpenLayers.Layer.Google(
- this.name, this.getOptions()
- );
- },
- /**
- * APIMethod: setVisibility
- * Set the visibility flag for the layer and hide/show & redraw
- * accordingly. Fire event unless otherwise specified
- *
- * Note that visibility is no longer simply whether or not the layer's
- * style.display is set to "block". Now we store a 'visibility' state
- * property on the layer class, this allows us to remember whether or
- * not we *desire* for a layer to be visible. In the case where the
- * map's resolution is out of the layer's range, this desire may be
- * subverted.
- *
- * Parameters:
- * visible - {Boolean} Display the layer (if in range)
- */
- setVisibility: function(visible) {
- // sharing a map container, opacity has to be set per layer
- var opacity = this.opacity == null ? 1 : this.opacity;
- OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments);
- this.setOpacity(opacity);
- },
-
- /**
- * APIMethod: display
- * Hide or show the Layer
- *
- * Parameters:
- * visible - {Boolean}
- */
- display: function(visible) {
- if (!this._dragging) {
- this.setGMapVisibility(visible);
- }
- OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
- },
-
- /**
- * Method: moveTo
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
- * do some init work in that case.
- * dragging - {Boolean}
- */
- moveTo: function(bounds, zoomChanged, dragging) {
- this._dragging = dragging;
- OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments);
- delete this._dragging;
- },
-
- /**
- * APIMethod: setOpacity
- * Sets the opacity for the entire layer (all images)
- *
- * Parameters:
- * opacity - {Float}
- */
- setOpacity: function(opacity) {
- if (opacity !== this.opacity) {
- if (this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "opacity"
- });
- }
- this.opacity = opacity;
- }
- // Though this layer's opacity may not change, we're sharing a container
- // and need to update the opacity for the entire container.
- if (this.getVisibility()) {
- var container = this.getMapContainer();
- OpenLayers.Util.modifyDOMElement(
- container, null, null, null, null, null, null, opacity
- );
- }
- },
- /**
- * APIMethod: destroy
- * Clean up this layer.
- */
- destroy: function() {
- /**
- * We have to override this method because the event pane destroy
- * deletes the mapObject reference before removing this layer from
- * the map.
- */
- if (this.map) {
- this.setGMapVisibility(false);
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache && cache.count <= 1) {
- this.removeGMapElements();
- }
- }
- OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: removeGMapElements
- * Remove all elements added to the dom. This should only be called if
- * this is the last of the Google layers for the given map.
- */
- removeGMapElements: function() {
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache) {
- // remove shared elements from dom
- var container = this.mapObject && this.getMapContainer();
- if (container && container.parentNode) {
- container.parentNode.removeChild(container);
- }
- var termsOfUse = cache.termsOfUse;
- if (termsOfUse && termsOfUse.parentNode) {
- termsOfUse.parentNode.removeChild(termsOfUse);
- }
- var poweredBy = cache.poweredBy;
- if (poweredBy && poweredBy.parentNode) {
- poweredBy.parentNode.removeChild(poweredBy);
- }
- }
- },
- /**
- * APIMethod: removeMap
- * On being removed from the map, also remove termsOfUse and poweredBy divs
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- // hide layer before removing
- if (this.visibility && this.mapObject) {
- this.setGMapVisibility(false);
- }
- // check to see if last Google layer in this map
- var cache = OpenLayers.Layer.Google.cache[map.id];
- if (cache) {
- if (cache.count <= 1) {
- this.removeGMapElements();
- delete OpenLayers.Layer.Google.cache[map.id];
- } else {
- // decrement the layer count
- --cache.count;
- }
- }
- // remove references to gmap elements
- delete this.termsOfUse;
- delete this.poweredBy;
- delete this.mapObject;
- delete this.dragObject;
- OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
- },
-
- //
- // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
- //
- /**
- * APIMethod: getOLBoundsFromMapObjectBounds
- *
- * Parameters:
- * moBounds - {Object}
- *
- * Returns:
- * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the
- * passed-in MapObject Bounds.
- * Returns null if null value is passed in.
- */
- getOLBoundsFromMapObjectBounds: function(moBounds) {
- var olBounds = null;
- if (moBounds != null) {
- var sw = moBounds.getSouthWest();
- var ne = moBounds.getNorthEast();
- if (this.sphericalMercator) {
- sw = this.forwardMercator(sw.lng(), sw.lat());
- ne = this.forwardMercator(ne.lng(), ne.lat());
- } else {
- sw = new OpenLayers.LonLat(sw.lng(), sw.lat());
- ne = new OpenLayers.LonLat(ne.lng(), ne.lat());
- }
- olBounds = new OpenLayers.Bounds(sw.lon,
- sw.lat,
- ne.lon,
- ne.lat );
- }
- return olBounds;
- },
- /**
- * APIMethod: getWarningHTML
- *
- * Returns:
- * {String} String with information on why layer is broken, how to get
- * it working.
- */
- getWarningHTML:function() {
- return OpenLayers.i18n("googleWarning");
- },
- /************************************
- * *
- * MapObject Interface Controls *
- * *
- ************************************/
- // Get&Set Center, Zoom
- /**
- * APIMethod: getMapObjectCenter
- *
- * Returns:
- * {Object} The mapObject's current center in Map Object format
- */
- getMapObjectCenter: function() {
- return this.mapObject.getCenter();
- },
- /**
- * APIMethod: getMapObjectZoom
- *
- * Returns:
- * {Integer} The mapObject's current zoom, in Map Object format
- */
- getMapObjectZoom: function() {
- return this.mapObject.getZoom();
- },
-
- /************************************
- * *
- * MapObject Primitives *
- * *
- ************************************/
- // LonLat
-
- /**
- * APIMethod: getLongitudeFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Float} Longitude of the given MapObject LonLat
- */
- getLongitudeFromMapObjectLonLat: function(moLonLat) {
- return this.sphericalMercator ?
- this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
- moLonLat.lng();
- },
- /**
- * APIMethod: getLatitudeFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Float} Latitude of the given MapObject LonLat
- */
- getLatitudeFromMapObjectLonLat: function(moLonLat) {
- var lat = this.sphericalMercator ?
- this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
- moLonLat.lat();
- return lat;
- },
-
- // Pixel
-
- /**
- * APIMethod: getXFromMapObjectPixel
- *
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Integer} X value of the MapObject Pixel
- */
- getXFromMapObjectPixel: function(moPixel) {
- return moPixel.x;
- },
- /**
- * APIMethod: getYFromMapObjectPixel
- *
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Integer} Y value of the MapObject Pixel
- */
- getYFromMapObjectPixel: function(moPixel) {
- return moPixel.y;
- },
-
- CLASS_NAME: "OpenLayers.Layer.Google"
- });
- /**
- * Property: OpenLayers.Layer.Google.cache
- * {Object} Cache for elements that should only be created once per map.
- */
- OpenLayers.Layer.Google.cache = {};
- /**
- * Constant: OpenLayers.Layer.Google.v2
- *
- * Mixin providing functionality specific to the Google Maps API v2.
- *
- * This API has been deprecated by Google.
- * Developers are encouraged to migrate to v3 of the API; support for this
- * is provided by <OpenLayers.Layer.Google.v3>
- */
- OpenLayers.Layer.Google.v2 = {
-
- /**
- * Property: termsOfUse
- * {DOMElement} Div for Google's copyright and terms of use link
- */
- termsOfUse: null,
- /**
- * Property: poweredBy
- * {DOMElement} Div for Google's powered by logo and link
- */
- poweredBy: null,
- /**
- * Property: dragObject
- * {GDraggableObject} Since 2.93, Google has exposed the ability to get
- * the maps GDraggableObject. We can now use this for smooth panning
- */
- dragObject: null,
-
- /**
- * Method: loadMapObject
- * Load the GMap and register appropriate event listeners. If we can't
- * load GMap2, then display a warning message.
- */
- loadMapObject:function() {
- if (!this.type) {
- this.type = G_NORMAL_MAP;
- }
- var mapObject, termsOfUse, poweredBy;
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache) {
- // there are already Google layers added to this map
- mapObject = cache.mapObject;
- termsOfUse = cache.termsOfUse;
- poweredBy = cache.poweredBy;
- // increment the layer count
- ++cache.count;
- } else {
- // this is the first Google layer for this map
- var container = this.map.viewPortDiv;
- var div = document.createElement("div");
- div.id = this.map.id + "_GMap2Container";
- div.style.position = "absolute";
- div.style.width = "100%";
- div.style.height = "100%";
- container.appendChild(div);
- // create GMap and shuffle elements
- try {
- mapObject = new GMap2(div);
-
- // move the ToS and branding stuff up to the container div
- termsOfUse = div.lastChild;
- container.appendChild(termsOfUse);
- termsOfUse.style.zIndex = "1100";
- termsOfUse.style.right = "";
- termsOfUse.style.bottom = "";
- termsOfUse.className = "olLayerGoogleCopyright";
- poweredBy = div.lastChild;
- container.appendChild(poweredBy);
- poweredBy.style.zIndex = "1100";
- poweredBy.style.right = "";
- poweredBy.style.bottom = "";
- poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
-
- } catch (e) {
- throw(e);
- }
- // cache elements for use by any other google layers added to
- // this same map
- OpenLayers.Layer.Google.cache[this.map.id] = {
- mapObject: mapObject,
- termsOfUse: termsOfUse,
- poweredBy: poweredBy,
- count: 1
- };
- }
- this.mapObject = mapObject;
- this.termsOfUse = termsOfUse;
- this.poweredBy = poweredBy;
-
- // ensure this layer type is one of the mapObject types
- if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
- this.type) === -1) {
- this.mapObject.addMapType(this.type);
- }
- //since v 2.93 getDragObject is now available.
- if(typeof mapObject.getDragObject == "function") {
- this.dragObject = mapObject.getDragObject();
- } else {
- this.dragPanMapObject = null;
- }
-
- if(this.isBaseLayer === false) {
- this.setGMapVisibility(this.div.style.display !== "none");
- }
- },
- /**
- * APIMethod: onMapResize
- */
- onMapResize: function() {
- // workaround for resizing of invisible or not yet fully loaded layers
- // where GMap2.checkResize() does not work. We need to load the GMap
- // for the old div size, then checkResize(), and then call
- // layer.moveTo() to trigger GMap.setCenter() (which will finish
- // the GMap initialization).
- if(this.visibility && this.mapObject.isLoaded()) {
- this.mapObject.checkResize();
- } else {
- if(!this._resized) {
- var layer = this;
- var handle = GEvent.addListener(this.mapObject, "load", function() {
- GEvent.removeListener(handle);
- delete layer._resized;
- layer.mapObject.checkResize();
- layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
- });
- }
- this._resized = true;
- }
- },
- /**
- * Method: setGMapVisibility
- * Display the GMap container and associated elements.
- *
- * Parameters:
- * visible - {Boolean} Display the GMap elements.
- */
- setGMapVisibility: function(visible) {
- var cache = OpenLayers.Layer.Google.cache[this.map.id];
- if (cache) {
- var container = this.mapObject.getContainer();
- if (visible === true) {
- this.mapObject.setMapType(this.type);
- container.style.display = "";
- this.termsOfUse.style.left = "";
- this.termsOfUse.style.display = "";
- this.poweredBy.style.display = "";
- cache.displayed = this.id;
- } else {
- if (cache.displayed === this.id) {
- delete cache.displayed;
- }
- if (!cache.displayed) {
- container.style.display = "none";
- this.termsOfUse.style.display = "none";
- // move ToU far to the left in addition to setting display
- // to "none", because at the end of the GMap2 load
- // sequence, display: none will be unset and ToU would be
- // visible after loading a map with a google layer that is
- // initially hidden.
- this.termsOfUse.style.left = "-9999px";
- this.poweredBy.style.display = "none";
- }
- }
- }
- },
-
- /**
- * Method: getMapContainer
- *
- * Returns:
- * {DOMElement} the GMap container's div
- */
- getMapContainer: function() {
- return this.mapObject.getContainer();
- },
- //
- // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
- //
- /**
- * APIMethod: getMapObjectBoundsFromOLBounds
- *
- * Parameters:
- * olBounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {Object} A MapObject Bounds, translated from olBounds
- * Returns null if null value is passed in
- */
- getMapObjectBoundsFromOLBounds: function(olBounds) {
- var moBounds = null;
- if (olBounds != null) {
- var sw = this.sphericalMercator ?
- this.inverseMercator(olBounds.bottom, olBounds.left) :
- new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
- var ne = this.sphericalMercator ?
- this.inverseMercator(olBounds.top, olBounds.right) :
- new OpenLayers.LonLat(olBounds.top, olBounds.right);
- moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
- new GLatLng(ne.lat, ne.lon));
- }
- return moBounds;
- },
- /************************************
- * *
- * MapObject Interface Controls *
- * *
- ************************************/
- // Get&Set Center, Zoom
- /**
- * APIMethod: setMapObjectCenter
- * Set the mapObject to the specified center and zoom
- *
- * Parameters:
- * center - {Object} MapObject LonLat format
- * zoom - {int} MapObject zoom format
- */
- setMapObjectCenter: function(center, zoom) {
- this.mapObject.setCenter(center, zoom);
- },
-
- /**
- * APIMethod: dragPanMapObject
- *
- * Parameters:
- * dX - {Integer}
- * dY - {Integer}
- */
- dragPanMapObject: function(dX, dY) {
- this.dragObject.moveBy(new GSize(-dX, dY));
- },
- // LonLat - Pixel Translation
-
- /**
- * APIMethod: getMapObjectLonLatFromMapObjectPixel
- *
- * Parameters:
- * moPixel - {Object} MapObject Pixel format
- *
- * Returns:
- * {Object} MapObject LonLat translated from MapObject Pixel
- */
- getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
- return this.mapObject.fromContainerPixelToLatLng(moPixel);
- },
- /**
- * APIMethod: getMapObjectPixelFromMapObjectLonLat
- *
- * Parameters:
- * moLonLat - {Object} MapObject LonLat format
- *
- * Returns:
- * {Object} MapObject Pixel transtlated from MapObject LonLat
- */
- getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
- return this.mapObject.fromLatLngToContainerPixel(moLonLat);
- },
-
- // Bounds
-
- /**
- * APIMethod: getMapObjectZoomFromMapObjectBounds
- *
- * Parameters:
- * moBounds - {Object} MapObject Bounds format
- *
- * Returns:
- * {Object} MapObject Zoom for specified MapObject Bounds
- */
- getMapObjectZoomFromMapObjectBounds: function(moBounds) {
- return this.mapObject.getBoundsZoomLevel(moBounds);
- },
- /************************************
- * *
- * MapObject Primitives *
- * *
- ************************************/
- // LonLat
-
- /**
- * APIMethod: getMapObjectLonLatFromLonLat
- *
- * Parameters:
- * lon - {Float}
- * lat - {Float}
- *
- * Returns:
- * {Object} MapObject LonLat built from lon and lat params
- */
- getMapObjectLonLatFromLonLat: function(lon, lat) {
- var gLatLng;
- if(this.sphericalMercator) {
- var lonlat = this.inverseMercator(lon, lat);
- gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
- } else {
- gLatLng = new GLatLng(lat, lon);
- }
- return gLatLng;
- },
- // Pixel
-
- /**
- * APIMethod: getMapObjectPixelFromXY
- *
- * Parameters:
- * x - {Integer}
- * y - {Integer}
- *
- * Returns:
- * {Object} MapObject Pixel from x and y parameters
- */
- getMapObjectPixelFromXY: function(x, y) {
- return new GPoint(x, y);
- }
-
- };
- /* ======================================================================
- OpenLayers/Format/XML.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format.js
- */
- /**
- * Class: OpenLayers.Format.XML
- * Read and write XML. For cross-browser XML generation, use methods on an
- * instance of the XML format class instead of on <code>document<end>.
- * The DOM creation and traversing methods exposed here all mimic the
- * W3C XML DOM methods. Create a new parser with the
- * <OpenLayers.Format.XML> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format>
- */
- OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs. Properties
- * of this object should not be set individually. Read-only. All
- * XML subclasses should have their own namespaces object. Use
- * <setNamespace> to add or set a namespace alias after construction.
- */
- namespaces: null,
-
- /**
- * Property: namespaceAlias
- * {Object} Mapping of namespace URI to namespace alias. This object
- * is read-only. Use <setNamespace> to add or set a namespace alias.
- */
- namespaceAlias: null,
-
- /**
- * Property: defaultPrefix
- * {String} The default namespace alias for creating element nodes.
- */
- defaultPrefix: null,
-
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {},
-
- /**
- * Property: writers
- * As a compliment to the <readers> property, this structure contains public
- * writing functions grouped by namespace alias and named like the
- * node names they produce.
- */
- writers: {},
- /**
- * Property: xmldom
- * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
- * object. It is not intended to be a browser sniffing property.
- * Instead, the xmldom property is used instead of <code>document<end>
- * where namespaced node creation methods are not supported. In all
- * other browsers, this remains null.
- */
- xmldom: null,
- /**
- * Constructor: OpenLayers.Format.XML
- * Construct an XML parser. The parser is used to read and write XML.
- * Reading XML from a string returns a DOM element. Writing XML from
- * a DOM element returns a string.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on
- * the object.
- */
- initialize: function(options) {
- if(window.ActiveXObject) {
- this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
- }
- OpenLayers.Format.prototype.initialize.apply(this, [options]);
- // clone the namespace object and set all namespace aliases
- this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
- this.namespaceAlias = {};
- for(var alias in this.namespaces) {
- this.namespaceAlias[this.namespaces[alias]] = alias;
- }
- },
-
- /**
- * APIMethod: destroy
- * Clean up.
- */
- destroy: function() {
- this.xmldom = null;
- OpenLayers.Format.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: setNamespace
- * Set a namespace alias and URI for the format.
- *
- * Parameters:
- * alias - {String} The namespace alias (prefix).
- * uri - {String} The namespace URI.
- */
- setNamespace: function(alias, uri) {
- this.namespaces[alias] = uri;
- this.namespaceAlias[uri] = alias;
- },
- /**
- * APIMethod: read
- * Deserialize a XML string and return a DOM node.
- *
- * Parameters:
- * text - {String} A XML string
-
- * Returns:
- * {DOMElement} A DOM node
- */
- read: function(text) {
- var index = text.indexOf('<');
- if(index > 0) {
- text = text.substring(index);
- }
- var node = OpenLayers.Util.Try(
- OpenLayers.Function.bind((
- function() {
- var xmldom;
- /**
- * Since we want to be able to call this method on the prototype
- * itself, this.xmldom may not exist even if in IE.
- */
- if(window.ActiveXObject && !this.xmldom) {
- xmldom = new ActiveXObject("Microsoft.XMLDOM");
- } else {
- xmldom = this.xmldom;
-
- }
- xmldom.loadXML(text);
- return xmldom;
- }
- ), this),
- function() {
- return new DOMParser().parseFromString(text, 'text/xml');
- },
- function() {
- var req = new XMLHttpRequest();
- req.open("GET", "data:" + "text/xml" +
- ";charset=utf-8," + encodeURIComponent(text), false);
- if(req.overrideMimeType) {
- req.overrideMimeType("text/xml");
- }
- req.send(null);
- return req.responseXML;
- }
- );
- if(this.keepData) {
- this.data = node;
- }
- return node;
- },
- /**
- * APIMethod: write
- * Serialize a DOM node into a XML string.
- *
- * Parameters:
- * node - {DOMElement} A DOM node.
- *
- * Returns:
- * {String} The XML string representation of the input node.
- */
- write: function(node) {
- var data;
- if(this.xmldom) {
- data = node.xml;
- } else {
- var serializer = new XMLSerializer();
- if (node.nodeType == 1) {
- // Add nodes to a document before serializing. Everything else
- // is serialized as is. This may need more work. See #1218 .
- var doc = document.implementation.createDocument("", "", null);
- if (doc.importNode) {
- node = doc.importNode(node, true);
- }
- doc.appendChild(node);
- data = serializer.serializeToString(doc);
- } else {
- data = serializer.serializeToString(node);
- }
- }
- return data;
- },
- /**
- * APIMethod: createElementNS
- * Create a new element with namespace. This node can be appended to
- * another node with the standard node.appendChild method. For
- * cross-browser support, this method must be used instead of
- * document.createElementNS.
- *
- * Parameters:
- * uri - {String} Namespace URI for the element.
- * name - {String} The qualified name of the element (prefix:localname).
- *
- * Returns:
- * {Element} A DOM element with namespace.
- */
- createElementNS: function(uri, name) {
- var element;
- if(this.xmldom) {
- if(typeof uri == "string") {
- element = this.xmldom.createNode(1, name, uri);
- } else {
- element = this.xmldom.createNode(1, name, "");
- }
- } else {
- element = document.createElementNS(uri, name);
- }
- return element;
- },
- /**
- * APIMethod: createTextNode
- * Create a text node. This node can be appended to another node with
- * the standard node.appendChild method. For cross-browser support,
- * this method must be used instead of document.createTextNode.
- *
- * Parameters:
- * text - {String} The text of the node.
- *
- * Returns:
- * {DOMElement} A DOM text node.
- */
- createTextNode: function(text) {
- var node;
- if (typeof text !== "string") {
- text = String(text);
- }
- if(this.xmldom) {
- node = this.xmldom.createTextNode(text);
- } else {
- node = document.createTextNode(text);
- }
- return node;
- },
- /**
- * APIMethod: getElementsByTagNameNS
- * Get a list of elements on a node given the namespace URI and local name.
- * To return all nodes in a given namespace, use '*' for the name
- * argument. To return all nodes of a given (local) name, regardless
- * of namespace, use '*' for the uri argument.
- *
- * Parameters:
- * node - {Element} Node on which to search for other nodes.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the tag (without the prefix).
- *
- * Returns:
- * {NodeList} A node list or array of elements.
- */
- getElementsByTagNameNS: function(node, uri, name) {
- var elements = [];
- if(node.getElementsByTagNameNS) {
- elements = node.getElementsByTagNameNS(uri, name);
- } else {
- // brute force method
- var allNodes = node.getElementsByTagName("*");
- var potentialNode, fullName;
- for(var i=0, len=allNodes.length; i<len; ++i) {
- potentialNode = allNodes[i];
- fullName = (potentialNode.prefix) ?
- (potentialNode.prefix + ":" + name) : name;
- if((name == "*") || (fullName == potentialNode.nodeName)) {
- if((uri == "*") || (uri == potentialNode.namespaceURI)) {
- elements.push(potentialNode);
- }
- }
- }
- }
- return elements;
- },
- /**
- * APIMethod: getAttributeNodeNS
- * Get an attribute node given the namespace URI and local name.
- *
- * Parameters:
- * node - {Element} Node on which to search for attribute nodes.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {DOMElement} An attribute node or null if none found.
- */
- getAttributeNodeNS: function(node, uri, name) {
- var attributeNode = null;
- if(node.getAttributeNodeNS) {
- attributeNode = node.getAttributeNodeNS(uri, name);
- } else {
- var attributes = node.attributes;
- var potentialNode, fullName;
- for(var i=0, len=attributes.length; i<len; ++i) {
- potentialNode = attributes[i];
- if(potentialNode.namespaceURI == uri) {
- fullName = (potentialNode.prefix) ?
- (potentialNode.prefix + ":" + name) : name;
- if(fullName == potentialNode.nodeName) {
- attributeNode = potentialNode;
- break;
- }
- }
- }
- }
- return attributeNode;
- },
- /**
- * APIMethod: getAttributeNS
- * Get an attribute value given the namespace URI and local name.
- *
- * Parameters:
- * node - {Element} Node on which to search for an attribute.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {String} An attribute value or and empty string if none found.
- */
- getAttributeNS: function(node, uri, name) {
- var attributeValue = "";
- if(node.getAttributeNS) {
- attributeValue = node.getAttributeNS(uri, name) || "";
- } else {
- var attributeNode = this.getAttributeNodeNS(node, uri, name);
- if(attributeNode) {
- attributeValue = attributeNode.nodeValue;
- }
- }
- return attributeValue;
- },
-
- /**
- * APIMethod: getChildValue
- * Get the textual value of the node if it exists, or return an
- * optional default string. Returns an empty string if no first child
- * exists and no default value is supplied.
- *
- * Parameters:
- * node - {DOMElement} The element used to look for a first child value.
- * def - {String} Optional string to return in the event that no
- * first child value exists.
- *
- * Returns:
- * {String} The value of the first child of the given node.
- */
- getChildValue: function(node, def) {
- var value = def || "";
- if(node) {
- for(var child=node.firstChild; child; child=child.nextSibling) {
- switch(child.nodeType) {
- case 3: // text node
- case 4: // cdata section
- value += child.nodeValue;
- }
- }
- }
- return value;
- },
- /**
- * APIMethod: isSimpleContent
- * Test if the given node has only simple content (i.e. no child element
- * nodes).
- *
- * Parameters:
- * node - {DOMElement} An element node.
- *
- * Returns:
- * {Boolean} The node has no child element nodes (nodes of type 1).
- */
- isSimpleContent: function(node) {
- var simple = true;
- for(var child=node.firstChild; child; child=child.nextSibling) {
- if(child.nodeType === 1) {
- simple = false;
- break;
- }
- }
- return simple;
- },
-
- /**
- * APIMethod: contentType
- * Determine the content type for a given node.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
- * if the node has no, simple, complex, or mixed content.
- */
- contentType: function(node) {
- var simple = false,
- complex = false;
-
- var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
- for(var child=node.firstChild; child; child=child.nextSibling) {
- switch(child.nodeType) {
- case 1: // element
- complex = true;
- break;
- case 8: // comment
- break;
- default:
- simple = true;
- }
- if(complex && simple) {
- break;
- }
- }
-
- if(complex && simple) {
- type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
- } else if(complex) {
- return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
- } else if(simple) {
- return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
- }
- return type;
- },
- /**
- * APIMethod: hasAttributeNS
- * Determine whether a node has a particular attribute matching the given
- * name and namespace.
- *
- * Parameters:
- * node - {Element} Node on which to search for an attribute.
- * uri - {String} Namespace URI.
- * name - {String} Local name of the attribute (without the prefix).
- *
- * Returns:
- * {Boolean} The node has an attribute matching the name and namespace.
- */
- hasAttributeNS: function(node, uri, name) {
- var found = false;
- if(node.hasAttributeNS) {
- found = node.hasAttributeNS(uri, name);
- } else {
- found = !!this.getAttributeNodeNS(node, uri, name);
- }
- return found;
- },
-
- /**
- * APIMethod: setAttributeNS
- * Adds a new attribute or changes the value of an attribute with the given
- * namespace and name.
- *
- * Parameters:
- * node - {Element} Element node on which to set the attribute.
- * uri - {String} Namespace URI for the attribute.
- * name - {String} Qualified name (prefix:localname) for the attribute.
- * value - {String} Attribute value.
- */
- setAttributeNS: function(node, uri, name, value) {
- if(node.setAttributeNS) {
- node.setAttributeNS(uri, name, value);
- } else {
- if(this.xmldom) {
- if(uri) {
- var attribute = node.ownerDocument.createNode(
- 2, name, uri
- );
- attribute.nodeValue = value;
- node.setAttributeNode(attribute);
- } else {
- node.setAttribute(name, value);
- }
- } else {
- throw "setAttributeNS not implemented";
- }
- }
- },
- /**
- * Method: createElementNSPlus
- * Shorthand for creating namespaced elements with optional attributes and
- * child text nodes.
- *
- * Parameters:
- * name - {String} The qualified node name.
- * options - {Object} Optional object for node configuration.
- *
- * Valid options:
- * uri - {String} Optional namespace uri for the element - supply a prefix
- * instead if the namespace uri is a property of the format's namespace
- * object.
- * attributes - {Object} Optional attributes to be set using the
- * <setAttributes> method.
- * value - {String} Optional text to be appended as a text node.
- *
- * Returns:
- * {Element} An element node.
- */
- createElementNSPlus: function(name, options) {
- options = options || {};
- // order of prefix preference
- // 1. in the uri option
- // 2. in the prefix option
- // 3. in the qualified name
- // 4. from the defaultPrefix
- var uri = options.uri || this.namespaces[options.prefix];
- if(!uri) {
- var loc = name.indexOf(":");
- uri = this.namespaces[name.substring(0, loc)];
- }
- if(!uri) {
- uri = this.namespaces[this.defaultPrefix];
- }
- var node = this.createElementNS(uri, name);
- if(options.attributes) {
- this.setAttributes(node, options.attributes);
- }
- var value = options.value;
- if(value != null) {
- node.appendChild(this.createTextNode(value));
- }
- return node;
- },
-
- /**
- * Method: setAttributes
- * Set multiple attributes given key value pairs from an object.
- *
- * Parameters:
- * node - {Element} An element node.
- * obj - {Object || Array} An object whose properties represent attribute
- * names and values represent attribute values. If an attribute name
- * is a qualified name ("prefix:local"), the prefix will be looked up
- * in the parsers {namespaces} object. If the prefix is found,
- * setAttributeNS will be used instead of setAttribute.
- */
- setAttributes: function(node, obj) {
- var value, uri;
- for(var name in obj) {
- if(obj[name] != null && obj[name].toString) {
- value = obj[name].toString();
- // check for qualified attribute name ("prefix:local")
- uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
- this.setAttributeNS(node, uri, name, value);
- }
- }
- },
- /**
- * Method: readNode
- * Shorthand for applying one of the named readers given the node
- * namespace and local name. Readers take two args (node, obj) and
- * generally extend or modify the second.
- *
- * Parameters:
- * node - {DOMElement} The node to be read (required).
- * obj - {Object} The object to be modified (optional).
- *
- * Returns:
- * {Object} The input object, modified (or a new one if none was provided).
- */
- readNode: function(node, obj) {
- if(!obj) {
- obj = {};
- }
- var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix];
- if(group) {
- var local = node.localName || node.nodeName.split(":").pop();
- var reader = group[local] || group["*"];
- if(reader) {
- reader.apply(this, [node, obj]);
- }
- }
- return obj;
- },
- /**
- * Method: readChildNodes
- * Shorthand for applying the named readers to all children of a node.
- * For each child of type 1 (element), <readSelf> is called.
- *
- * Parameters:
- * node - {DOMElement} The node to be read (required).
- * obj - {Object} The object to be modified (optional).
- *
- * Returns:
- * {Object} The input object, modified.
- */
- readChildNodes: function(node, obj) {
- if(!obj) {
- obj = {};
- }
- var children = node.childNodes;
- var child;
- for(var i=0, len=children.length; i<len; ++i) {
- child = children[i];
- if(child.nodeType == 1) {
- this.readNode(child, obj);
- }
- }
- return obj;
- },
- /**
- * Method: writeNode
- * Shorthand for applying one of the named writers and appending the
- * results to a node. If a qualified name is not provided for the
- * second argument (and a local name is used instead), the namespace
- * of the parent node will be assumed.
- *
- * Parameters:
- * name - {String} The name of a node to generate. If a qualified name
- * (e.g. "pre:Name") is used, the namespace prefix is assumed to be
- * in the <writers> group. If a local name is used (e.g. "Name") then
- * the namespace of the parent is assumed. If a local name is used
- * and no parent is supplied, then the default namespace is assumed.
- * obj - {Object} Structure containing data for the writer.
- * parent - {DOMElement} Result will be appended to this node. If no parent
- * is supplied, the node will not be appended to anything.
- *
- * Returns:
- * {DOMElement} The child node.
- */
- writeNode: function(name, obj, parent) {
- var prefix, local;
- var split = name.indexOf(":");
- if(split > 0) {
- prefix = name.substring(0, split);
- local = name.substring(split + 1);
- } else {
- if(parent) {
- prefix = this.namespaceAlias[parent.namespaceURI];
- } else {
- prefix = this.defaultPrefix;
- }
- local = name;
- }
- var child = this.writers[prefix][local].apply(this, [obj]);
- if(parent) {
- parent.appendChild(child);
- }
- return child;
- },
- /**
- * APIMethod: getChildEl
- * Get the first child element. Optionally only return the first child
- * if it matches the given name and namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The parent node.
- * name - {String} Optional node name (local) to search for.
- * uri - {String} Optional namespace URI to search for.
- *
- * Returns:
- * {DOMElement} The first child. Returns null if no element is found, if
- * something significant besides an element is found, or if the element
- * found does not match the optional name and uri.
- */
- getChildEl: function(node, name, uri) {
- return node && this.getThisOrNextEl(node.firstChild, name, uri);
- },
-
- /**
- * APIMethod: getNextEl
- * Get the next sibling element. Optionally get the first sibling only
- * if it matches the given local name and namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The node.
- * name - {String} Optional local name of the sibling to search for.
- * uri - {String} Optional namespace URI of the sibling to search for.
- *
- * Returns:
- * {DOMElement} The next sibling element. Returns null if no element is
- * found, something significant besides an element is found, or the
- * found element does not match the optional name and uri.
- */
- getNextEl: function(node, name, uri) {
- return node && this.getThisOrNextEl(node.nextSibling, name, uri);
- },
-
- /**
- * Method: getThisOrNextEl
- * Return this node or the next element node. Optionally get the first
- * sibling with the given local name or namespace URI.
- *
- * Parameters:
- * node - {DOMElement} The node.
- * name - {String} Optional local name of the sibling to search for.
- * uri - {String} Optional namespace URI of the sibling to search for.
- *
- * Returns:
- * {DOMElement} The next sibling element. Returns null if no element is
- * found, something significant besides an element is found, or the
- * found element does not match the query.
- */
- getThisOrNextEl: function(node, name, uri) {
- outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
- switch(sibling.nodeType) {
- case 1: // Element
- if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
- (!uri || uri === sibling.namespaceURI)) {
- // matches
- break outer;
- }
- sibling = null;
- break outer;
- case 3: // Text
- if(/^\s*$/.test(sibling.nodeValue)) {
- break;
- }
- case 4: // CDATA
- case 6: // ENTITY_NODE
- case 12: // NOTATION_NODE
- case 10: // DOCUMENT_TYPE_NODE
- case 11: // DOCUMENT_FRAGMENT_NODE
- sibling = null;
- break outer;
- } // ignore comments and processing instructions
- }
- return sibling || null;
- },
-
- /**
- * APIMethod: lookupNamespaceURI
- * Takes a prefix and returns the namespace URI associated with it on the given
- * node if found (and null if not). Supplying null for the prefix will
- * return the default namespace.
- *
- * For browsers that support it, this calls the native lookupNamesapceURI
- * function. In other browsers, this is an implementation of
- * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
- *
- * For browsers that don't support the attribute.ownerElement property, this
- * method cannot be called on attribute nodes.
- *
- * Parameters:
- * node - {DOMElement} The node from which to start looking.
- * prefix - {String} The prefix to lookup or null to lookup the default namespace.
- *
- * Returns:
- * {String} The namespace URI for the given prefix. Returns null if the prefix
- * cannot be found or the node is the wrong type.
- */
- lookupNamespaceURI: function(node, prefix) {
- var uri = null;
- if(node) {
- if(node.lookupNamespaceURI) {
- uri = node.lookupNamespaceURI(prefix);
- } else {
- outer: switch(node.nodeType) {
- case 1: // ELEMENT_NODE
- if(node.namespaceURI !== null && node.prefix === prefix) {
- uri = node.namespaceURI;
- break outer;
- }
- var len = node.attributes.length;
- if(len) {
- var attr;
- for(var i=0; i<len; ++i) {
- attr = node.attributes[i];
- if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
- uri = attr.value || null;
- break outer;
- } else if(attr.name === "xmlns" && prefix === null) {
- uri = attr.value || null;
- break outer;
- }
- }
- }
- uri = this.lookupNamespaceURI(node.parentNode, prefix);
- break outer;
- case 2: // ATTRIBUTE_NODE
- uri = this.lookupNamespaceURI(node.ownerElement, prefix);
- break outer;
- case 9: // DOCUMENT_NODE
- uri = this.lookupNamespaceURI(node.documentElement, prefix);
- break outer;
- case 6: // ENTITY_NODE
- case 12: // NOTATION_NODE
- case 10: // DOCUMENT_TYPE_NODE
- case 11: // DOCUMENT_FRAGMENT_NODE
- break outer;
- default:
- // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
- // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
- uri = this.lookupNamespaceURI(node.parentNode, prefix);
- break outer;
- }
- }
- }
- return uri;
- },
-
- /**
- * Method: getXMLDoc
- * Get an XML document for nodes that are not supported in HTML (e.g.
- * createCDATASection). On IE, this will either return an existing or
- * create a new <xmldom> on the instance. On other browsers, this will
- * either return an existing or create a new shared document (see
- * <OpenLayers.Format.XML.document>).
- *
- * Returns:
- * {XMLDocument}
- */
- getXMLDoc: function() {
- if (!OpenLayers.Format.XML.document && !this.xmldom) {
- if (document.implementation && document.implementation.createDocument) {
- OpenLayers.Format.XML.document =
- document.implementation.createDocument("", "", null);
- } else if (!this.xmldom && window.ActiveXObject) {
- this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
- }
- }
- return OpenLayers.Format.XML.document || this.xmldom;
- },
- CLASS_NAME: "OpenLayers.Format.XML"
- });
- OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
- /**
- * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
- * Takes a prefix and returns the namespace URI associated with it on the given
- * node if found (and null if not). Supplying null for the prefix will
- * return the default namespace.
- *
- * For browsers that support it, this calls the native lookupNamesapceURI
- * function. In other browsers, this is an implementation of
- * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
- *
- * For browsers that don't support the attribute.ownerElement property, this
- * method cannot be called on attribute nodes.
- *
- * Parameters:
- * node - {DOMElement} The node from which to start looking.
- * prefix - {String} The prefix to lookup or null to lookup the default namespace.
- *
- * Returns:
- * {String} The namespace URI for the given prefix. Returns null if the prefix
- * cannot be found or the node is the wrong type.
- */
- OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
- OpenLayers.Format.XML.prototype.lookupNamespaceURI,
- OpenLayers.Format.XML.prototype
- );
- /**
- * Property: OpenLayers.Format.XML.document
- * {XMLDocument} XML document to reuse for creating non-HTML compliant nodes,
- * like document.createCDATASection.
- */
- OpenLayers.Format.XML.document = null;
- /* ======================================================================
- OpenLayers/Format/WFST.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format.js
- */
- /**
- * Function: OpenLayers.Format.WFST
- * Used to create a versioned WFS protocol. Default version is 1.0.0.
- *
- * Returns:
- * {<OpenLayers.Format>} A WFST format of the given version.
- */
- OpenLayers.Format.WFST = function(options) {
- options = OpenLayers.Util.applyDefaults(
- options, OpenLayers.Format.WFST.DEFAULTS
- );
- var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
- if(!cls) {
- throw "Unsupported WFST version: " + options.version;
- }
- return new cls(options);
- };
- /**
- * Constant: OpenLayers.Format.WFST.DEFAULTS
- * {Object} Default properties for the WFST format.
- */
- OpenLayers.Format.WFST.DEFAULTS = {
- "version": "1.0.0"
- };
- /* ======================================================================
- OpenLayers/Format/WFST/v1.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format/XML.js
- * @requires OpenLayers/Format/WFST.js
- */
- /**
- * Class: OpenLayers.Format.WFST.v1
- * Superclass for WFST parsers.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
- OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- xlink: "http://www.w3.org/1999/xlink",
- xsi: "http://www.w3.org/2001/XMLSchema-instance",
- wfs: "http://www.opengis.net/wfs",
- gml: "http://www.opengis.net/gml",
- ogc: "http://www.opengis.net/ogc",
- ows: "http://www.opengis.net/ows"
- },
-
- /**
- * Property: defaultPrefix
- */
- defaultPrefix: "wfs",
- /**
- * Property: version
- * {String} WFS version number.
- */
- version: null,
- /**
- * Property: schemaLocation
- * {String} Schema location for a particular minor version.
- */
- schemaLocations: null,
-
- /**
- * APIProperty: srsName
- * {String} URI for spatial reference system.
- */
- srsName: null,
- /**
- * APIProperty: extractAttributes
- * {Boolean} Extract attributes from GML. Default is true.
- */
- extractAttributes: true,
-
- /**
- * APIProperty: xy
- * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
- * Changing is not recommended, a new Format should be instantiated.
- */
- xy: true,
- /**
- * Property: stateName
- * {Object} Maps feature states to node names.
- */
- stateName: null,
-
- /**
- * Constructor: OpenLayers.Format.WFST.v1
- * Instances of this class are not created directly. Use the
- * <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
- * constructor instead.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(options) {
- // set state name mapping
- this.stateName = {};
- this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
- this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
- this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * Method: getSrsName
- */
- getSrsName: function(feature, options) {
- var srsName = options && options.srsName;
- if(!srsName) {
- if(feature && feature.layer) {
- srsName = feature.layer.projection.getCode();
- } else {
- srsName = this.srsName;
- }
- }
- return srsName;
- },
- /**
- * APIMethod: read
- * Parse the response from a transaction. Because WFS is split into
- * Transaction requests (create, update, and delete) and GetFeature
- * requests (read), this method handles parsing of both types of
- * responses.
- *
- * Parameters:
- * data - {String | Document} The WFST document to read
- * options - {Object} Options for the reader
- *
- * Valid options properties:
- * output - {String} either "features" or "object". The default is
- * "features", which means that the method will return an array of
- * features. If set to "object", an object with a "features" property
- * and other properties read by the parser will be returned.
- *
- * Returns:
- * {Array | Object} Output depending on the output option.
- */
- read: function(data, options) {
- options = options || {};
- OpenLayers.Util.applyDefaults(options, {
- output: "features"
- });
-
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
- if(data && data.nodeType == 9) {
- data = data.documentElement;
- }
- var obj = {};
- if(data) {
- this.readNode(data, obj, true);
- }
- if(obj.features && options.output === "features") {
- obj = obj.features;
- }
- return obj;
- },
-
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {
- "wfs": {
- "FeatureCollection": function(node, obj) {
- obj.features = [];
- this.readChildNodes(node, obj);
- }
- }
- },
-
- /**
- * Method: write
- * Given an array of features, write a WFS transaction. This assumes
- * the features have a state property that determines the operation
- * type - insert, update, or delete.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. See
- * below for a more detailed description of the influence of the
- * feature's *modified* property.
- * options - {Object}
- *
- * feature.modified rules:
- * If a feature has a modified property set, the following checks will be
- * made before a feature's geometry or attribute is included in an Update
- * transaction:
- * - *modified* is not set at all: The geometry and all attributes will be
- * included.
- * - *modified.geometry* is set (null or a geometry): The geometry will be
- * included. If *modified.attributes* is not set, all attributes will
- * be included.
- * - *modified.attributes* is set: Only the attributes set (i.e. to null or
- * a value) in *modified.attributes* will be included.
- * If *modified.geometry* is not set, the geometry will not be included.
- *
- * Valid options include:
- * - *multi* {Boolean} If set to true, geometries will be casted to
- * Multi geometries before writing.
- *
- * Returns:
- * {String} A serialized WFS transaction.
- */
- write: function(features, options) {
- var node = this.writeNode("wfs:Transaction", {
- features:features,
- options: options
- });
- var value = this.schemaLocationAttr();
- if(value) {
- this.setAttributeNS(
- node, this.namespaces["xsi"], "xsi:schemaLocation", value
- );
- }
- return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
- },
-
- /**
- * Property: writers
- * As a compliment to the readers property, this structure contains public
- * writing functions grouped by namespace alias and named like the
- * node names they produce.
- */
- writers: {
- "wfs": {
- "GetFeature": function(options) {
- var node = this.createElementNSPlus("wfs:GetFeature", {
- attributes: {
- service: "WFS",
- version: this.version,
- handle: options && options.handle,
- outputFormat: options && options.outputFormat,
- maxFeatures: options && options.maxFeatures,
- "xsi:schemaLocation": this.schemaLocationAttr(options)
- }
- });
- if (typeof this.featureType == "string") {
- this.writeNode("Query", options, node);
- } else {
- for (var i=0,len = this.featureType.length; i<len; i++) {
- options.featureType = this.featureType[i];
- this.writeNode("Query", options, node);
- }
- }
- return node;
- },
- "Transaction": function(obj) {
- obj = obj || {};
- var options = obj.options || {};
- var node = this.createElementNSPlus("wfs:Transaction", {
- attributes: {
- service: "WFS",
- version: this.version,
- handle: options.handle
- }
- });
- var i, len;
- var features = obj.features;
- if(features) {
- // temporarily re-assigning geometry types
- if (options.multi === true) {
- OpenLayers.Util.extend(this.geometryTypes, {
- "OpenLayers.Geometry.Point": "MultiPoint",
- "OpenLayers.Geometry.LineString": (this.multiCurve === true) ? "MultiCurve": "MultiLineString",
- "OpenLayers.Geometry.Polygon": (this.multiSurface === true) ? "MultiSurface" : "MultiPolygon"
- });
- }
- var name, feature;
- for(i=0, len=features.length; i<len; ++i) {
- feature = features[i];
- name = this.stateName[feature.state];
- if(name) {
- this.writeNode(name, {
- feature: feature,
- options: options
- }, node);
- }
- }
- // switch back to original geometry types assignment
- if (options.multi === true) {
- this.setGeometryTypes();
- }
- }
- if (options.nativeElements) {
- for (i=0, len=options.nativeElements.length; i<len; ++i) {
- this.writeNode("wfs:Native",
- options.nativeElements[i], node);
- }
- }
- return node;
- },
- "Native": function(nativeElement) {
- var node = this.createElementNSPlus("wfs:Native", {
- attributes: {
- vendorId: nativeElement.vendorId,
- safeToIgnore: nativeElement.safeToIgnore
- },
- value: nativeElement.value
- });
- return node;
- },
- "Insert": function(obj) {
- var feature = obj.feature;
- var options = obj.options;
- var node = this.createElementNSPlus("wfs:Insert", {
- attributes: {
- handle: options && options.handle
- }
- });
- this.srsName = this.getSrsName(feature);
- this.writeNode("feature:_typeName", feature, node);
- return node;
- },
- "Update": function(obj) {
- var feature = obj.feature;
- var options = obj.options;
- var node = this.createElementNSPlus("wfs:Update", {
- attributes: {
- handle: options && options.handle,
- typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
- this.featureType
- }
- });
- if(this.featureNS) {
- node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
- }
-
- // add in geometry
- var modified = feature.modified;
- if (this.geometryName !== null && (!modified || modified.geometry !== undefined)) {
- this.srsName = this.getSrsName(feature);
- this.writeNode(
- "Property", {name: this.geometryName, value: feature.geometry}, node
- );
- }
-
- // add in attributes
- for(var key in feature.attributes) {
- if(feature.attributes[key] !== undefined &&
- (!modified || !modified.attributes ||
- (modified.attributes && modified.attributes[key] !== undefined))) {
- this.writeNode(
- "Property", {name: key, value: feature.attributes[key]}, node
- );
- }
- }
-
- // add feature id filter
- this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
- fids: [feature.fid]
- }), node);
-
- return node;
- },
- "Property": function(obj) {
- var node = this.createElementNSPlus("wfs:Property");
- this.writeNode("Name", obj.name, node);
- if(obj.value !== null) {
- this.writeNode("Value", obj.value, node);
- }
- return node;
- },
- "Name": function(name) {
- return this.createElementNSPlus("wfs:Name", {value: name});
- },
- "Value": function(obj) {
- var node;
- if(obj instanceof OpenLayers.Geometry) {
- node = this.createElementNSPlus("wfs:Value");
- var geom = this.writeNode("feature:_geometry", obj).firstChild;
- node.appendChild(geom);
- } else {
- node = this.createElementNSPlus("wfs:Value", {value: obj});
- }
- return node;
- },
- "Delete": function(obj) {
- var feature = obj.feature;
- var options = obj.options;
- var node = this.createElementNSPlus("wfs:Delete", {
- attributes: {
- handle: options && options.handle,
- typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
- this.featureType
- }
- });
- if(this.featureNS) {
- node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
- }
- this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
- fids: [feature.fid]
- }), node);
- return node;
- }
- }
- },
- /**
- * Method: schemaLocationAttr
- * Generate the xsi:schemaLocation attribute value.
- *
- * Returns:
- * {String} The xsi:schemaLocation attribute or undefined if none.
- */
- schemaLocationAttr: function(options) {
- options = OpenLayers.Util.extend({
- featurePrefix: this.featurePrefix,
- schema: this.schema
- }, options);
- var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
- if(options.schema) {
- schemaLocations[options.featurePrefix] = options.schema;
- }
- var parts = [];
- var uri;
- for(var key in schemaLocations) {
- uri = this.namespaces[key];
- if(uri) {
- parts.push(uri + " " + schemaLocations[key]);
- }
- }
- var value = parts.join(" ") || undefined;
- return value;
- },
-
- /**
- * Method: setFilterProperty
- * Set the property of each spatial filter.
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>}
- */
- setFilterProperty: function(filter) {
- if(filter.filters) {
- for(var i=0, len=filter.filters.length; i<len; ++i) {
- OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this, filter.filters[i]);
- }
- } else {
- if(filter instanceof OpenLayers.Filter.Spatial && !filter.property) {
- // got a spatial filter without property, so set it
- filter.property = this.geometryName;
- }
- }
- },
- CLASS_NAME: "OpenLayers.Format.WFST.v1"
- });
- /* ======================================================================
- OpenLayers/Format/OGCExceptionReport.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format/XML.js
- */
- /**
- * Class: OpenLayers.Format.OGCExceptionReport
- * Class to read exception reports for various OGC services and versions.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
- OpenLayers.Format.OGCExceptionReport = OpenLayers.Class(OpenLayers.Format.XML, {
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- ogc: "http://www.opengis.net/ogc"
- },
- /**
- * Property: regExes
- * Compiled regular expressions for manipulating strings.
- */
- regExes: {
- trimSpace: (/^\s*|\s*$/g),
- removeSpace: (/\s*/g),
- splitSpace: (/\s+/),
- trimComma: (/\s*,\s*/g)
- },
- /**
- * Property: defaultPrefix
- */
- defaultPrefix: "ogc",
- /**
- * Constructor: OpenLayers.Format.OGCExceptionReport
- * Create a new parser for OGC exception reports.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- /**
- * APIMethod: read
- * Read OGC exception report data from a string, and return an object with
- * information about the exceptions.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- *
- * Returns:
- * {Object} Information about the exceptions that occurred.
- */
- read: function(data) {
- var result;
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
- var root = data.documentElement;
- var exceptionInfo = {exceptionReport: null};
- if (root) {
- this.readChildNodes(data, exceptionInfo);
- if (exceptionInfo.exceptionReport === null) {
- // fall-back to OWSCommon since this is a common output format for exceptions
- // we cannot easily use the ows readers directly since they differ for 1.0 and 1.1
- exceptionInfo = new OpenLayers.Format.OWSCommon().read(data);
- }
- }
- return exceptionInfo;
- },
- /**
- * Property: readers
- * Contains public functions, grouped by namespace prefix, that will
- * be applied when a namespaced node is found matching the function
- * name. The function will be applied in the scope of this parser
- * with two arguments: the node being read and a context object passed
- * from the parent.
- */
- readers: {
- "ogc": {
- "ServiceExceptionReport": function(node, obj) {
- obj.exceptionReport = {exceptions: []};
- this.readChildNodes(node, obj.exceptionReport);
- },
- "ServiceException": function(node, exceptionReport) {
- var exception = {
- code: node.getAttribute("code"),
- locator: node.getAttribute("locator"),
- text: this.getChildValue(node)
- };
- exceptionReport.exceptions.push(exception);
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Format.OGCExceptionReport"
-
- });
- /* ======================================================================
- OpenLayers/Format/XML/VersionedOGC.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Format/XML.js
- * @requires OpenLayers/Format/OGCExceptionReport.js
- */
- /**
- * Class: OpenLayers.Format.XML.VersionedOGC
- * Base class for versioned formats, i.e. a format which supports multiple
- * versions.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
- OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * APIProperty: defaultVersion
- * {String} Version number to assume if none found.
- */
- defaultVersion: null,
-
- /**
- * APIProperty: version
- * {String} Specify a version string if one is known.
- */
- version: null,
- /**
- * APIProperty: profile
- * {String} If provided, use a custom profile.
- */
- profile: null,
- /**
- * APIProperty: errorProperty
- * {String} Which property of the returned object to check for in order to
- * determine whether or not parsing has failed. In the case that the
- * errorProperty is undefined on the returned object, the document will be
- * run through an OGCExceptionReport parser.
- */
- errorProperty: null,
- /**
- * Property: name
- * {String} The name of this parser, this is the part of the CLASS_NAME
- * except for "OpenLayers.Format."
- */
- name: null,
- /**
- * APIProperty: stringifyOutput
- * {Boolean} If true, write will return a string otherwise a DOMElement.
- * Default is false.
- */
- stringifyOutput: false,
- /**
- * Property: parser
- * {Object} Instance of the versioned parser. Cached for multiple read and
- * write calls of the same version.
- */
- parser: null,
- /**
- * Constructor: OpenLayers.Format.XML.VersionedOGC.
- * Constructor.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on
- * the object.
- */
- initialize: function(options) {
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- var className = this.CLASS_NAME;
- this.name = className.substring(className.lastIndexOf(".")+1);
- },
- /**
- * Method: getVersion
- * Returns the version to use. Subclasses can override this function
- * if a different version detection is needed.
- *
- * Parameters:
- * root - {DOMElement}
- * options - {Object} Optional configuration object.
- *
- * Returns:
- * {String} The version to use.
- */
- getVersion: function(root, options) {
- var version;
- // read
- if (root) {
- version = this.version;
- if(!version) {
- version = root.getAttribute("version");
- if(!version) {
- version = this.defaultVersion;
- }
- }
- } else { // write
- version = (options && options.version) ||
- this.version || this.defaultVersion;
- }
- return version;
- },
- /**
- * Method: getParser
- * Get an instance of the cached parser if available, otherwise create one.
- *
- * Parameters:
- * version - {String}
- *
- * Returns:
- * {<OpenLayers.Format>}
- */
- getParser: function(version) {
- version = version || this.defaultVersion;
- var profile = this.profile ? "_" + this.profile : "";
- if(!this.parser || this.parser.VERSION != version) {
- var format = OpenLayers.Format[this.name][
- "v" + version.replace(/\./g, "_") + profile
- ];
- if(!format) {
- throw "Can't find a " + this.name + " parser for version " +
- version + profile;
- }
- this.parser = new format(this.options);
- }
- return this.parser;
- },
- /**
- * APIMethod: write
- * Write a document.
- *
- * Parameters:
- * obj - {Object} An object representing the document.
- * options - {Object} Optional configuration object.
- *
- * Returns:
- * {String} The document as a string
- */
- write: function(obj, options) {
- var version = this.getVersion(null, options);
- this.parser = this.getParser(version);
- var root = this.parser.write(obj, options);
- if (this.stringifyOutput === false) {
- return root;
- } else {
- return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
- }
- },
- /**
- * APIMethod: read
- * Read a doc and return an object representing the document.
- *
- * Parameters:
- * data - {String | DOMElement} Data to read.
- * options - {Object} Options for the reader.
- *
- * Returns:
- * {Object} An object representing the document.
- */
- read: function(data, options) {
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
- var root = data.documentElement;
- var version = this.getVersion(root);
- this.parser = this.getParser(version);
- var obj = this.parser.read(data, options);
- if (this.errorProperty !== null && obj[this.errorProperty] === undefined) {
- // an error must have happened, so parse it and report back
- var format = new OpenLayers.Format.OGCExceptionReport();
- obj.error = format.read(data);
- }
- obj.version = version;
- return obj;
- },
- CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC"
- });
- /* ======================================================================
- OpenLayers/Feature.js
- ====================================================================== */
- /* Copyright (c) 2006-2012 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/Class.js
- * @requires OpenLayers/Util.js
- */
- /**
- * Class: OpenLayers.Feature
- * Features are combinations of geography and attributes. The OpenLayers.Feature
- * class specifically combines a marker and a lonlat.
- */
- OpenLayers.Feature = OpenLayers.Class({
- /**
- * Property: layer
- * {<OpenLayers.Layer>}
- */
- layer: null,
- /**
- * Property: