summaryrefslogtreecommitdiff
path: root/misc/openlayers/OpenLayers.mobile.debug.js
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/OpenLayers.mobile.debug.js')
-rw-r--r--misc/openlayers/OpenLayers.mobile.debug.js41831
1 files changed, 0 insertions, 41831 deletions
diff --git a/misc/openlayers/OpenLayers.mobile.debug.js b/misc/openlayers/OpenLayers.mobile.debug.js
deleted file mode 100644
index 5cb37cd..0000000
--- a/misc/openlayers/OpenLayers.mobile.debug.js
+++ /dev/null
@@ -1,41831 +0,0 @@
-/*
-
- OpenLayers.js -- OpenLayers Map Viewer Library
-
- Copyright (c) 2006-2013 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-var OpenLayers = {
- /**
- * Constant: VERSION_NUMBER
- */
- VERSION_NUMBER: "Release 2.13.1",
-
- /**
- * 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.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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;
- }
- if (replacement === undefined) {
- break;
- }
- 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}
- * trimWhitespace - {Boolean}
- *
- * Returns:
- * {Number|String} a Number if the passed value is a number, a String
- * otherwise.
- */
- numericIf: function(value, trimWhitespace) {
- var originalValue = value;
- if (trimWhitespace === true && value != null && value.replace) {
- value = value.replace(/^\s*|\s*$/g, "");
- }
- return OpenLayers.String.isNumeric(value) ? parseFloat(value) : originalValue;
- }
-
-};
-
-/**
- * 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;
- },
-
- /**
- * Method: zeroPad
- * Create a zero padded string optionally with a radix for casting numbers.
- *
- * Parameters:
- * num - {Number} The number to be zero padded.
- * len - {Number} The length of the string to be returned.
- * radix - {Number} An integer between 2 and 36 specifying the base to use
- * for representing numeric values.
- */
- zeroPad: function(num, len, radix) {
- var str = num.toString(radix || 10);
- while (str.length < len) {
- str = "0" + str;
- }
- 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/Class.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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/Bounds.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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 less 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 a string representation of the bounds object.
- *
- * Returns:
- * {String} String representation of bounds object.
- */
- toString:function() {
- return [this.left, this.bottom, this.right, this.top].join(",");
- },
-
- /**
- * APIMethod: toArray
- * Returns an array representation of the bounds object.
- *
- * Returns an array of left, bottom, right, top properties, or -- when the
- * optional parameter is true -- an array of the bottom, left, top,
- * right properties.
- *
- * 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
- * Returns a boundingbox-string representation of the bounds object.
- *
- * 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. "5,42,10,45")
- */
- 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 the width of the bounds.
- *
- * Returns:
- * {Float} The width of the bounds (right minus left).
- */
- getWidth:function() {
- return (this.right - this.left);
- },
-
- /**
- * APIMethod: getHeight
- * Returns the height of the bounds.
- *
- * Returns:
- * {Float} The height of the bounds (top minus bottom).
- */
- getHeight:function() {
- return (this.top - this.bottom);
- },
-
- /**
- * APIMethod: getSize
- * Returns an <OpenLayers.Size> object of the bounds.
- *
- * Returns:
- * {<OpenLayers.Size>} The size of the bounds.
- */
- getSize:function() {
- return new OpenLayers.Size(this.getWidth(), this.getHeight());
- },
-
- /**
- * APIMethod: getCenterPixel
- * Returns the <OpenLayers.Pixel> object which represents the center of the
- * bounds.
- *
- * 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 the <OpenLayers.LonLat> object which represents the center of the
- * bounds.
- *
- * 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
- * Shifts the coordinates of the bound by the given horizontal and vertical
- * deltas.
- *
- * (start code)
- * var bounds = new OpenLayers.Bounds(0, 0, 10, 10);
- * bounds.toString();
- * // => "0,0,10,10"
- *
- * bounds.add(-1.5, 4).toString();
- * // => "-1.5,4,8.5,14"
- * (end)
- *
- * This method will throw a TypeError if it is passed null as an argument.
- *
- * Parameters:
- * x - {Float} horizontal delta
- * y - {Float} vertical delta
- *
- * 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 <OpenLayers.LonLat>,
- * <OpenLayers.Geometry.Point> or <OpenLayers.Bounds> specified.
- *
- * Please note that this function assumes that left < right and
- * bottom < top.
- *
- * Parameters:
- * object - {<OpenLayers.LonLat>, <OpenLayers.Geometry.Point> or
- * <OpenLayers.Bounds>} The object to be included in the new bounds
- * object.
- */
- extend:function(object) {
- if (object) {
- switch(object.CLASS_NAME) {
- case "OpenLayers.LonLat":
- this.extendXY(object.lon, object.lat);
- break;
- case "OpenLayers.Geometry.Point":
- this.extendXY(object.x, object.y);
- break;
-
- case "OpenLayers.Bounds":
- // clear cached center location
- this.centerLonLat = null;
-
- if ( (this.left == null) || (object.left < this.left)) {
- this.left = object.left;
- }
- if ( (this.bottom == null) || (object.bottom < this.bottom) ) {
- this.bottom = object.bottom;
- }
- if ( (this.right == null) || (object.right > this.right) ) {
- this.right = object.right;
- }
- if ( (this.top == null) || (object.top > this.top) ) {
- this.top = object.top;
- }
- break;
- }
- }
- },
-
- /**
- * APIMethod: extendXY
- * Extend the bounds to include the XY coordinate specified.
- *
- * Parameters:
- * x - {number} The X part of the the coordinate.
- * y - {number} The Y part of the the coordinate.
- */
- extendXY:function(x, y) {
- // clear cached center location
- this.centerLonLat = null;
-
- if ((this.left == null) || (x < this.left)) {
- this.left = x;
- }
- if ((this.bottom == null) || (y < this.bottom)) {
- this.bottom = y;
- }
- if ((this.right == null) || (x > this.right)) {
- this.right = x;
- }
- if ((this.top == null) || (y > this.top)) {
- this.top = y;
- }
- },
-
- /**
- * APIMethod: containsLonLat
- * Returns whether the bounds object contains the given <OpenLayers.LonLat>.
- *
- * 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
- * Returns whether the bounds object contains the given <OpenLayers.Pixel>.
- *
- * 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
- * Returns whether the bounds object contains the given x and y.
- *
- * 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
- * Returns whether the bounds object contains the given <OpenLayers.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
- * Returns the the quadrant ("br", "tr", "tl", "bl") in which the given
- * <OpenLayers.LonLat> lies.
- *
- * 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
- * Wraps the bounds object around the dateline.
- *
- * 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.
- *
- * (begin code)
- * OpenLayers.Bounds.fromString("5,42,10,45");
- * // => equivalent to ...
- * new OpenLayers.Bounds(5, 42, 10, 45);
- * (end)
- *
- * Parameters:
- * str - {String} Comma-separated bounds string. (e.g. "5,42,10,45")
- * 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.
- *
- * (begin code)
- * OpenLayers.Bounds.fromArray( [5, 42, 10, 45] );
- * // => equivalent to ...
- * new OpenLayers.Bounds(5, 42, 10, 45);
- * (end)
- *
- * Parameters:
- * bbox - {Array(Float)} Array of bounds values (e.g. [5,42,10,45])
- * 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.
- *
- * (begin code)
- * OpenLayers.Bounds.fromSize( new OpenLayers.Size(10, 20) );
- * // => equivalent to ...
- * new OpenLayers.Bounds(0, 20, 10, 0);
- * (end)
- *
- * Parameters:
- * size - {<OpenLayers.Size> or Object} <OpenLayers.Size> or an object with
- * both '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.
- *
- * (begin code)
- * OpenLayers.Bounds.oppositeQuadrant( "tl" );
- * // => "br"
- *
- * OpenLayers.Bounds.oppositeQuadrant( "tr" );
- * // => "bl"
- * (end)
- *
- * 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/BaseTypes/Bounds.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/BaseTypes/LonLat.js
- * @requires OpenLayers/BaseTypes/Pixel.js
- * @requires OpenLayers/BaseTypes/Size.js
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Namespace: Util
- */
-OpenLayers.Util = OpenLayers.Util || {};
-
-/**
- * Function: getElement
- * This is the old $() from prototype
- *
- * Parameters:
- * e - {String or DOMElement or Window}
- *
- * Returns:
- * {Array(DOMElement) or DOMElement}
- */
-OpenLayers.Util.getElement = function() {
- var elements = [];
-
- for (var i=0, len=arguments.length; i<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]');
-};
-
-/**
- * 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;
- }
-};
-
-
-/**
- * Property: dotless
- * {RegExp}
- * Compiled regular expression to match dots ("."). This is used for replacing
- * dots in identifiers. Because object identifiers are frequently used for
- * DOM element identifiers by the library, we avoid using dots to make for
- * more sensible CSS selectors.
- *
- * TODO: Use a module pattern to avoid bloating the API with stuff like this.
- */
-OpenLayers.Util.dotless = /\./g;
-
-/**
- * Function: modifyDOMElement
- *
- * Modifies many properties of a DOM element all at once. Passing in
- * null to an individual parameter will avoid setting the attribute.
- *
- * Parameters:
- * element - {DOMElement} DOM element to modify.
- * id - {String} The element id attribute to set. Note that dots (".") will be
- * replaced with underscore ("_") in setting the element id.
- * px - {<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.replace(OpenLayers.Util.dotless, "_");
- }
- if (px) {
- element.style.left = px.x + "px";
- element.style.top = px.y + "px";
- }
- if (sz) {
- element.style.width = sz.w + "px";
- element.style.height = sz.h + "px";
- }
- if (position) {
- element.style.position = position;
- }
- if (border) {
- element.style.border = border;
- }
- if (overflow) {
- element.style.overflow = overflow;
- }
- if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
- element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
- element.style.opacity = opacity;
- } else if (parseFloat(opacity) == 1.0) {
- element.style.filter = '';
- element.style.opacity = '';
- }
-};
-
-/**
- * Function: createDiv
- * Creates a new div and optionally set some standard attributes.
- * Null may be passed to each parameter if you do not wish to
- * set a particular attribute.
- * Note - zIndex is NOT set on the resulting div.
- *
- * Parameters:
- * id - {String} An identifier for this element. If no id is
- * passed an identifier will be created
- * automatically. Note that dots (".") will be replaced with
- * underscore ("_") when generating ids.
- * px - {<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.
- * options - {Object} Additional options. Optional.
- *
- * Valid options:
- * splitArgs - {Boolean} Split comma delimited params into arrays? Default is
- * true.
- *
- * Returns:
- * {Object} An object of key/value pairs from the query string.
- */
-OpenLayers.Util.getParameters = function(url, options) {
- options = options || {};
- // if no url specified, take it from the location bar
- url = (url === null || url === undefined) ? window.location.href : url;
-
- //parse out parameters portion of url string
- var paramsString = "";
- if (OpenLayers.String.contains(url, '?')) {
- var start = url.indexOf('?') + 1;
- var end = OpenLayers.String.contains(url, "#") ?
- url.indexOf('#') : url.length;
- paramsString = url.substring(start, end);
- }
-
- var parameters = {};
- var pairs = paramsString.split(/[&;]/);
- for(var i=0, len=pairs.length; i<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
- if (options.splitArgs !== false) {
- 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_".
- * Note that dots (".") in the prefix will be replaced with underscore ("_").
- *
- * Returns:
- * {String} A unique id string, built on the passed in prefix.
- */
-OpenLayers.Util.createUniqueID = function(prefix) {
- if (prefix == null) {
- prefix = "id_";
- } else {
- prefix = prefix.replace(OpenLayers.Util.dotless, "_");
- }
- 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.37,
- 'km': 39370,
- '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 = window.pageYOffset || viewportElement.scrollTop;
- var scrollLeft = window.pageXOffset || viewportElement.scrollLeft;
-
- pos[0] = box.left + scrollLeft;
- pos[1] = box.top + scrollTop;
-
- } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko
- // Gecko ignores the scroll values for ancestors, up to 1.9. See:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
- // https://bugzilla.mozilla.org/show_bug.cgi?id=330619
-
- box = document.getBoxObjectFor(forElement);
- var vpBox = document.getBoxObjectFor(viewportElement);
- pos[0] = box.screenX - vpBox.screenX;
- pos[1] = box.screenY - vpBox.screenY;
-
- } else { // safari/opera
- pos[0] = forElement.offsetLeft;
- pos[1] = forElement.offsetTop;
- parent = forElement.offsetParent;
- if (parent != forElement) {
- while (parent) {
- pos[0] += parent.offsetLeft;
- pos[1] += parent.offsetTop;
- parent = parent.offsetParent;
- }
- }
-
- var browser = OpenLayers.BROWSER_NAME;
-
- // opera & (safari absolute) incorrectly account for body offsetTop
- if (browser == "opera" || (browser == "safari" &&
- OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
- pos[1] -= document.body.offsetTop;
- }
-
- // accumulate the scroll positions for everything but the body element
- parent = forElement.offsetParent;
- while (parent && parent != document.body) {
- pos[0] -= parent.scrollLeft;
- // see https://bugs.opera.com/show_bug.cgi?id=249965
- if (browser != "opera" || parent.tagName != 'TR') {
- pos[1] -= parent.scrollTop;
- }
- parent = parent.offsetParent;
- }
- }
-
- return pos;
-};
-
-/**
- * Function: getViewportElement
- * Returns die viewport element of the document. The viewport element is
- * usually document.documentElement, except in IE,where it is either
- * document.body or document.documentElement, depending on the document's
- * compatibility mode (see
- * http://code.google.com/p/doctype/wiki/ArticleClientViewportElement)
- *
- * Returns:
- * {DOMElement}
- */
-OpenLayers.Util.getViewportElement = function() {
- var viewportElement = arguments.callee.viewportElement;
- if (viewportElement == undefined) {
- viewportElement = (OpenLayers.BROWSER_NAME == "msie" &&
- document.compatMode != 'CSS1Compat') ? document.body :
- document.documentElement;
- arguments.callee.viewportElement = viewportElement;
- }
- return viewportElement;
-};
-
-/**
- * Function: isEquivalentUrl
- * Test two URLs for equivalence.
- *
- * Setting 'ignoreCase' allows for case-independent comparison.
- *
- * Comparison is based on:
- * - Protocol
- * - Host (evaluated without the port)
- * - Port (set 'ignorePort80' to ignore "80" values)
- * - Hash ( set 'ignoreHash' to disable)
- * - Pathname (for relative <-> absolute comparison)
- * - Arguments (so they can be out of order)
- *
- * Parameters:
- * url1 - {String}
- * url2 - {String}
- * options - {Object} Allows for customization of comparison:
- * 'ignoreCase' - Default is True
- * 'ignorePort80' - Default is True
- * 'ignoreHash' - Default is True
- *
- * Returns:
- * {Boolean} Whether or not the two URLs are equivalent
- */
-OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
- options = options || {};
-
- OpenLayers.Util.applyDefaults(options, {
- ignoreCase: true,
- ignorePort80: true,
- ignoreHash: true,
- splitArgs: false
- });
-
- var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
- var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
-
- //compare all keys except for "args" (treated below)
- for(var key in urlObj1) {
- if(key !== "args") {
- if(urlObj1[key] != urlObj2[key]) {
- return false;
- }
- }
- }
-
- // compare search args - irrespective of order
- for(var key in urlObj1.args) {
- if(urlObj1.args[key] != urlObj2.args[key]) {
- return false;
- }
- delete urlObj2.args[key];
- }
- // urlObj2 shouldn't have any args left
- for(var key in urlObj2.args) {
- return false;
- }
-
- return true;
-};
-
-/**
- * Function: createUrlObject
- *
- * Parameters:
- * url - {String}
- * options - {Object} A hash of options.
- *
- * Valid options:
- * ignoreCase - {Boolean} lowercase url,
- * ignorePort80 - {Boolean} don't include explicit port if port is 80,
- * ignoreHash - {Boolean} Don't include part of url after the hash (#).
- * splitArgs - {Boolean} Split comma delimited params into arrays? Default is
- * true.
- *
- * Returns:
- * {Object} An object with separate url, a, port, host, and args parsed out
- * and ready for comparison
- */
-OpenLayers.Util.createUrlObject = function(url, options) {
- options = options || {};
-
- // deal with relative urls first
- if(!(/^\w+:\/\//).test(url)) {
- var loc = window.location;
- var port = loc.port ? ":" + loc.port : "";
- var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port;
- if(url.indexOf("/") === 0) {
- // full pathname
- url = fullUrl + url;
- } else {
- // relative to current path
- var parts = loc.pathname.split("/");
- parts.pop();
- url = fullUrl + parts.join("/") + "/" + url;
- }
- }
-
- if (options.ignoreCase) {
- url = url.toLowerCase();
- }
-
- var a = document.createElement('a');
- a.href = url;
-
- var urlObject = {};
-
- //host (without port)
- urlObject.host = a.host.split(":").shift();
-
- //protocol
- urlObject.protocol = a.protocol;
-
- //port (get uniform browser behavior with port 80 here)
- if(options.ignorePort80) {
- urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port;
- } else {
- urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port;
- }
-
- //hash
- urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;
-
- //args
- var queryString = a.search;
- if (!queryString) {
- var qMark = url.indexOf("?");
- queryString = (qMark != -1) ? url.substr(qMark) : "";
- }
- urlObject.args = OpenLayers.Util.getParameters(queryString,
- {splitArgs: options.splitArgs});
-
- // pathname
- //
- // This is a workaround for Internet Explorer where
- // window.location.pathname has a leading "/", but
- // a.pathname has no leading "/".
- urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
-
- return urlObject;
-};
-
-/**
- * Function: removeTail
- * Takes a url and removes everything after the ? and #
- *
- * Parameters:
- * url - {String} The url to process
- *
- * Returns:
- * {String} The string with all queryString and Hash removed
- */
-OpenLayers.Util.removeTail = function(url) {
- var head = null;
-
- var qMark = url.indexOf("?");
- var hashMark = url.indexOf("#");
-
- if (qMark == -1) {
- head = (hashMark != -1) ? url.substr(0,hashMark) : url;
- } else {
- head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
- : url.substr(0, qMark);
- }
- return head;
-};
-
-/**
- * Constant: IS_GECKO
- * {Boolean} True if the userAgent reports the browser to use the Gecko engine
- */
-OpenLayers.IS_GECKO = (function() {
- var ua = navigator.userAgent.toLowerCase();
- return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1;
-})();
-
-/**
- * Constant: CANVAS_SUPPORTED
- * {Boolean} True if canvas 2d is supported.
- */
-OpenLayers.CANVAS_SUPPORTED = (function() {
- var elem = document.createElement('canvas');
- return !!(elem.getContext && elem.getContext('2d'));
-})();
-
-/**
- * Constant: BROWSER_NAME
- * {String}
- * A substring of the navigator.userAgent property. Depending on the userAgent
- * property, this will be the empty string or one of the following:
- * * "opera" -- Opera
- * * "msie" -- Internet Explorer
- * * "safari" -- Safari
- * * "firefox" -- Firefox
- * * "mozilla" -- Mozilla
- */
-OpenLayers.BROWSER_NAME = (function() {
- var name = "";
- var ua = navigator.userAgent.toLowerCase();
- if (ua.indexOf("opera") != -1) {
- name = "opera";
- } else if (ua.indexOf("msie") != -1) {
- name = "msie";
- } else if (ua.indexOf("safari") != -1) {
- name = "safari";
- } else if (ua.indexOf("mozilla") != -1) {
- if (ua.indexOf("firefox") != -1) {
- name = "firefox";
- } else {
- name = "mozilla";
- }
- }
- return name;
-})();
-
-/**
- * Function: getBrowserName
- *
- * Returns:
- * {String} A string which specifies which is the current
- * browser in which we are running.
- *
- * Currently-supported browser detection and codes:
- * * 'opera' -- Opera
- * * 'msie' -- Internet Explorer
- * * 'safari' -- Safari
- * * 'firefox' -- Firefox
- * * 'mozilla' -- Mozilla
- *
- * If we are unable to property identify the browser, we
- * return an empty string.
- */
-OpenLayers.Util.getBrowserName = function() {
- return OpenLayers.BROWSER_NAME;
-};
-
-/**
- * Method: getRenderedDimensions
- * Renders the contentHTML offscreen to determine actual dimensions for
- * popup sizing. As we need layout to determine dimensions the content
- * is rendered -9999px to the left and absolute to ensure the
- * scrollbars do not flicker
- *
- * Parameters:
- * contentHTML
- * size - {<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/Events.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/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) {
- OpenLayers.Event.preventDefault(event);
- }
-
- if (event.stopPropagation) {
- event.stopPropagation();
- } else {
- event.cancelBubble = true;
- }
- },
-
- /**
- * Method: preventDefault
- * Cancels the event if it is cancelable, without stopping further
- * propagation of the event.
- *
- * Parameters:
- * event - {Event}
- */
- preventDefault: function(event) {
- if (event.preventDefault) {
- event.preventDefault();
- } else {
- event.returnValue = false;
- }
- },
-
- /**
- * 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];
- OpenLayers.Event.stopObserving.apply(this, [
- entry.element, entry.name, entry.observer, entry.useCapture
- ]);
- }
- }
- },
-
- /**
- * 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 = {};
- this._msTouches = [];
-
- // 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;
- var msTouch = !!window.navigator.msMaxTouchPoints;
- var type;
- for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) {
- type = this.BROWSER_EVENTS[i];
- // register the event cross-browser
- OpenLayers.Event.observe(element, type, this.eventHandler
- );
- if (msTouch && type.indexOf('touch') === 0) {
- this.addMsTouchListener(element, type, 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 || Object} will be passed to the listeners.
- *
- * 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 = this.getTouchClientXY(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);
- },
-
- /**
- * Method: getTouchClientXY
- * WebKit has a few bugs for clientX/clientY. This method detects them
- * and calculate the correct values.
- *
- * Parameters:
- * evt - {Touch} a Touch object from a TouchEvent
- *
- * Returns:
- * {Object} An object with only clientX and clientY properties with the
- * calculated values.
- */
- getTouchClientXY: function (evt) {
- // olMochWin is to override window, used for testing
- var win = window.olMockWin || window,
- winPageX = win.pageXOffset,
- winPageY = win.pageYOffset,
- x = evt.clientX,
- y = evt.clientY;
-
- if (evt.pageY === 0 && Math.floor(y) > Math.floor(evt.pageY) ||
- evt.pageX === 0 && Math.floor(x) > Math.floor(evt.pageX)) {
- // iOS4 include scroll offset in clientX/Y
- x = x - winPageX;
- y = y - winPageY;
- } else if (y < (evt.pageY - winPageY) || x < (evt.pageX - winPageX) ) {
- // Some Android browsers have totally bogus values for clientX/Y
- // when scrolling/zooming a page
- x = evt.pageX - winPageX;
- y = evt.pageY - winPageY;
- }
-
- evt.olClientX = x;
- evt.olClientY = y;
-
- return {
- clientX: x,
- clientY: y
- };
- },
-
- /**
- * 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;
- 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 = [
- window.pageXOffset || viewportElement.scrollLeft,
- window.pageYOffset || 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]
- );
- },
-
- /**
- * Method: addMsTouchListener
- *
- * Parameters:
- * element - {DOMElement} The DOM element to register the listener on
- * type - {String} The event type
- * handler - {Function} the handler
- */
- addMsTouchListener: function (element, type, handler) {
- var eventHandler = this.eventHandler;
- var touches = this._msTouches;
-
- function msHandler(evt) {
- handler(OpenLayers.Util.applyDefaults({
- stopPropagation: function() {
- for (var i=touches.length-1; i>=0; --i) {
- touches[i].stopPropagation();
- }
- },
- preventDefault: function() {
- for (var i=touches.length-1; i>=0; --i) {
- touches[i].preventDefault();
- }
- },
- type: type
- }, evt));
- }
-
- switch (type) {
- case 'touchstart':
- return this.addMsTouchListenerStart(element, type, msHandler);
- case 'touchend':
- return this.addMsTouchListenerEnd(element, type, msHandler);
- case 'touchmove':
- return this.addMsTouchListenerMove(element, type, msHandler);
- default:
- throw 'Unknown touch event type';
- }
- },
-
- /**
- * Method: addMsTouchListenerStart
- *
- * Parameters:
- * element - {DOMElement} The DOM element to register the listener on
- * type - {String} The event type
- * handler - {Function} the handler
- */
- addMsTouchListenerStart: function(element, type, handler) {
- var touches = this._msTouches;
-
- var cb = function(e) {
-
- var alreadyInArray = false;
- for (var i=0, ii=touches.length; i<ii; ++i) {
- if (touches[i].pointerId == e.pointerId) {
- alreadyInArray = true;
- break;
- }
- }
- if (!alreadyInArray) {
- touches.push(e);
- }
-
- e.touches = touches.slice();
- handler(e);
- };
-
- OpenLayers.Event.observe(element, 'MSPointerDown', cb);
-
- // Need to also listen for end events to keep the _msTouches list
- // accurate
- var internalCb = function(e) {
- for (var i=0, ii=touches.length; i<ii; ++i) {
- if (touches[i].pointerId == e.pointerId) {
- touches.splice(i, 1);
- break;
- }
- }
- };
- OpenLayers.Event.observe(element, 'MSPointerUp', internalCb);
- },
-
- /**
- * Method: addMsTouchListenerMove
- *
- * Parameters:
- * element - {DOMElement} The DOM element to register the listener on
- * type - {String} The event type
- * handler - {Function} the handler
- */
- addMsTouchListenerMove: function (element, type, handler) {
- var touches = this._msTouches;
- var cb = function(e) {
-
- //Don't fire touch moves when mouse isn't down
- if (e.pointerType == e.MSPOINTER_TYPE_MOUSE && e.buttons == 0) {
- return;
- }
-
- if (touches.length == 1 && touches[0].pageX == e.pageX &&
- touches[0].pageY == e.pageY) {
- // don't trigger event when pointer has not moved
- return;
- }
- for (var i=0, ii=touches.length; i<ii; ++i) {
- if (touches[i].pointerId == e.pointerId) {
- touches[i] = e;
- break;
- }
- }
-
- e.touches = touches.slice();
- handler(e);
- };
-
- OpenLayers.Event.observe(element, 'MSPointerMove', cb);
- },
-
- /**
- * Method: addMsTouchListenerEnd
- *
- * Parameters:
- * element - {DOMElement} The DOM element to register the listener on
- * type - {String} The event type
- * handler - {Function} the handler
- */
- addMsTouchListenerEnd: function (element, type, handler) {
- var touches = this._msTouches;
-
- var cb = function(e) {
-
- for (var i=0, ii=touches.length; i<ii; ++i) {
- if (touches[i].pointerId == e.pointerId) {
- touches.splice(i, 1);
- break;
- }
- }
-
- e.touches = touches.slice();
- handler(e);
- };
-
- OpenLayers.Event.observe(element, 'MSPointerUp', cb);
- },
-
- CLASS_NAME: "OpenLayers.Events"
-});
-/* ======================================================================
- OpenLayers/Events/buttonclick.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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: ignore
- * Check for event target elements that should be ignored by OpenLayers.
- *
- * Parameters:
- * element - {DOMElement} The event target.
- */
- ignore: function(element) {
- var depth = 3,
- ignore = false;
- do {
- if (element.nodeName.toLowerCase() === 'a') {
- ignore = true;
- break;
- }
- element = element.parentNode;
- } while (--depth > 0 && element);
- return ignore;
- },
-
- /**
- * 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);
- var viewportElement = OpenLayers.Util.getViewportElement();
- var scrollTop = window.pageYOffset || viewportElement.scrollTop;
- var scrollLeft = window.pageXOffset || viewportElement.scrollLeft;
- pos[0] = pos[0] - scrollLeft;
- pos[1] = pos[1] - scrollTop;
-
- 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 {
- propagate = !this.ignore(OpenLayers.Event.element(evt));
- delete this.startEvt;
- }
- }
- return propagate;
- }
-
-});
-/* ======================================================================
- OpenLayers/Control.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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: handlerOptions
- * {Object} Used to set non-default properties on the control's handler
- */
- handlerOptions: 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/Geometry.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- */
-
-/**
- * Class: OpenLayers.Geometry
- * A Geometry is a description of a geographic object. Create an instance of
- * this class with the <OpenLayers.Geometry> constructor. This is a base class,
- * typical geometry types are described by subclasses of this class.
- *
- * Note that if you use the <OpenLayers.Geometry.fromWKT> method, you must
- * explicitly include the OpenLayers.Format.WKT in your build.
- */
-OpenLayers.Geometry = OpenLayers.Class({
-
- /**
- * Property: id
- * {String} A unique identifier for this geometry.
- */
- id: null,
-
- /**
- * Property: parent
- * {<OpenLayers.Geometry>}This is set when a Geometry is added as component
- * of another geometry
- */
- parent: null,
-
- /**
- * Property: bounds
- * {<OpenLayers.Bounds>} The bounds of this geometry
- */
- bounds: null,
-
- /**
- * Constructor: OpenLayers.Geometry
- * Creates a geometry object.
- */
- initialize: function() {
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_");
- },
-
- /**
- * Method: destroy
- * Destroy this geometry.
- */
- destroy: function() {
- this.id = null;
- this.bounds = null;
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this geometry. Does not set any non-standard
- * properties of the cloned geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry>} An exact clone of this geometry.
- */
- clone: function() {
- return new OpenLayers.Geometry();
- },
-
- /**
- * Method: setBounds
- * Set the bounds for this Geometry.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- setBounds: function(bounds) {
- if (bounds) {
- this.bounds = bounds.clone();
- }
- },
-
- /**
- * Method: clearBounds
- * Nullify this components bounds and that of its parent as well.
- */
- clearBounds: function() {
- this.bounds = null;
- if (this.parent) {
- this.parent.clearBounds();
- }
- },
-
- /**
- * Method: extendBounds
- * Extend the existing bounds to include the new bounds.
- * If geometry's bounds is not yet set, then set a new Bounds.
- *
- * Parameters:
- * newBounds - {<OpenLayers.Bounds>}
- */
- extendBounds: function(newBounds){
- var bounds = this.getBounds();
- if (!bounds) {
- this.setBounds(newBounds);
- } else {
- this.bounds.extend(newBounds);
- }
- },
-
- /**
- * APIMethod: getBounds
- * Get the bounds for this Geometry. If bounds is not set, it
- * is calculated again, this makes queries faster.
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getBounds: function() {
- if (this.bounds == null) {
- this.calculateBounds();
- }
- return this.bounds;
- },
-
- /**
- * APIMethod: calculateBounds
- * Recalculate the bounds for the geometry.
- */
- calculateBounds: function() {
- //
- // This should be overridden by subclasses.
- //
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options depend on the specific geometry type.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and x2 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- },
-
- /**
- * Method: atPoint
- * Note - This is only an approximation based on the bounds of the
- * geometry.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
- * object with a 'lon' and 'lat' properties.
- * toleranceLon - {float} Optional tolerance in Geometric Coords
- * toleranceLat - {float} Optional tolerance in Geographic Coords
- *
- * Returns:
- * {Boolean} Whether or not the geometry is at the specified location
- */
- atPoint: function(lonlat, toleranceLon, toleranceLat) {
- var atPoint = false;
- var bounds = this.getBounds();
- if ((bounds != null) && (lonlat != null)) {
-
- var dX = (toleranceLon != null) ? toleranceLon : 0;
- var dY = (toleranceLat != null) ? toleranceLat : 0;
-
- var toleranceBounds =
- new OpenLayers.Bounds(this.bounds.left - dX,
- this.bounds.bottom - dY,
- this.bounds.right + dX,
- this.bounds.top + dY);
-
- atPoint = toleranceBounds.containsLonLat(lonlat);
- }
- return atPoint;
- },
-
- /**
- * Method: getLength
- * Calculate the length of this geometry. This method is defined in
- * subclasses.
- *
- * Returns:
- * {Float} The length of the collection by summing its parts
- */
- getLength: function() {
- //to be overridden by geometries that actually have a length
- //
- return 0.0;
- },
-
- /**
- * Method: getArea
- * Calculate the area of this geometry. This method is defined in subclasses.
- *
- * Returns:
- * {Float} The area of the collection by summing its parts
- */
- getArea: function() {
- //to be overridden by geometries that actually have an area
- //
- return 0.0;
- },
-
- /**
- * APIMethod: getCentroid
- * Calculate the centroid of this geometry. This method is defined in subclasses.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} The centroid of the collection
- */
- getCentroid: function() {
- return null;
- },
-
- /**
- * Method: toString
- * Returns a text representation of the geometry. If the WKT format is
- * included in a build, this will be the Well-Known Text
- * representation.
- *
- * Returns:
- * {String} String representation of this geometry.
- */
- toString: function() {
- var string;
- if (OpenLayers.Format && OpenLayers.Format.WKT) {
- string = OpenLayers.Format.WKT.prototype.write(
- new OpenLayers.Feature.Vector(this)
- );
- } else {
- string = Object.prototype.toString.call(this);
- }
- return string;
- },
-
- CLASS_NAME: "OpenLayers.Geometry"
-});
-
-/**
- * Function: OpenLayers.Geometry.fromWKT
- * Generate a geometry given a Well-Known Text string. For this method to
- * work, you must include the OpenLayers.Format.WKT in your build
- * explicitly.
- *
- * Parameters:
- * wkt - {String} A string representing the geometry in Well-Known Text.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry of the appropriate class.
- */
-OpenLayers.Geometry.fromWKT = function(wkt) {
- var geom;
- if (OpenLayers.Format && OpenLayers.Format.WKT) {
- var format = OpenLayers.Geometry.fromWKT.format;
- if (!format) {
- format = new OpenLayers.Format.WKT();
- OpenLayers.Geometry.fromWKT.format = format;
- }
- var result = format.read(wkt);
- if (result instanceof OpenLayers.Feature.Vector) {
- geom = result.geometry;
- } else if (OpenLayers.Util.isArray(result)) {
- var len = result.length;
- var components = new Array(len);
- for (var i=0; i<len; ++i) {
- components[i] = result[i].geometry;
- }
- geom = new OpenLayers.Geometry.Collection(components);
- }
- }
- return geom;
-};
-
-/**
- * Method: OpenLayers.Geometry.segmentsIntersect
- * Determine whether two line segments intersect. Optionally calculates
- * and returns the intersection point. This function is optimized for
- * cases where seg1.x2 >= seg2.x1 || seg2.x2 >= seg1.x1. In those
- * obvious cases where there is no intersection, the function should
- * not be called.
- *
- * Parameters:
- * seg1 - {Object} Object representing a segment with properties x1, y1, x2,
- * and y2. The start point is represented by x1 and y1. The end point
- * is represented by x2 and y2. Start and end are ordered so that x1 < x2.
- * seg2 - {Object} Object representing a segment with properties x1, y1, x2,
- * and y2. The start point is represented by x1 and y1. The end point
- * is represented by x2 and y2. Start and end are ordered so that x1 < x2.
- * options - {Object} Optional properties for calculating the intersection.
- *
- * Valid options:
- * point - {Boolean} Return the intersection point. If false, the actual
- * intersection point will not be calculated. If true and the segments
- * intersect, the intersection point will be returned. If true and
- * the segments do not intersect, false will be returned. If true and
- * the segments are coincident, true will be returned.
- * tolerance - {Number} If a non-null value is provided, if the segments are
- * within the tolerance distance, this will be considered an intersection.
- * In addition, if the point option is true and the calculated intersection
- * is within the tolerance distance of an end point, the endpoint will be
- * returned instead of the calculated intersection. Further, if the
- * intersection is within the tolerance of endpoints on both segments, or
- * if two segment endpoints are within the tolerance distance of eachother
- * (but no intersection is otherwise calculated), an endpoint on the
- * first segment provided will be returned.
- *
- * Returns:
- * {Boolean | <OpenLayers.Geometry.Point>} The two segments intersect.
- * If the point argument is true, the return will be the intersection
- * point or false if none exists. If point is true and the segments
- * are coincident, return will be true (and the instersection is equal
- * to the shorter segment).
- */
-OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, options) {
- var point = options && options.point;
- var tolerance = options && options.tolerance;
- var intersection = false;
- var x11_21 = seg1.x1 - seg2.x1;
- var y11_21 = seg1.y1 - seg2.y1;
- var x12_11 = seg1.x2 - seg1.x1;
- var y12_11 = seg1.y2 - seg1.y1;
- var y22_21 = seg2.y2 - seg2.y1;
- var x22_21 = seg2.x2 - seg2.x1;
- var d = (y22_21 * x12_11) - (x22_21 * y12_11);
- var n1 = (x22_21 * y11_21) - (y22_21 * x11_21);
- var n2 = (x12_11 * y11_21) - (y12_11 * x11_21);
- if(d == 0) {
- // parallel
- if(n1 == 0 && n2 == 0) {
- // coincident
- intersection = true;
- }
- } else {
- var along1 = n1 / d;
- var along2 = n2 / d;
- if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) {
- // intersect
- if(!point) {
- intersection = true;
- } else {
- // calculate the intersection point
- var x = seg1.x1 + (along1 * x12_11);
- var y = seg1.y1 + (along1 * y12_11);
- intersection = new OpenLayers.Geometry.Point(x, y);
- }
- }
- }
- if(tolerance) {
- var dist;
- if(intersection) {
- if(point) {
- var segs = [seg1, seg2];
- var seg, x, y;
- // check segment endpoints for proximity to intersection
- // set intersection to first endpoint within the tolerance
- outer: for(var i=0; i<2; ++i) {
- seg = segs[i];
- for(var j=1; j<3; ++j) {
- x = seg["x" + j];
- y = seg["y" + j];
- dist = Math.sqrt(
- Math.pow(x - intersection.x, 2) +
- Math.pow(y - intersection.y, 2)
- );
- if(dist < tolerance) {
- intersection.x = x;
- intersection.y = y;
- break outer;
- }
- }
- }
-
- }
- } else {
- // no calculated intersection, but segments could be within
- // the tolerance of one another
- var segs = [seg1, seg2];
- var source, target, x, y, p, result;
- // check segment endpoints for proximity to intersection
- // set intersection to first endpoint within the tolerance
- outer: for(var i=0; i<2; ++i) {
- source = segs[i];
- target = segs[(i+1)%2];
- for(var j=1; j<3; ++j) {
- p = {x: source["x"+j], y: source["y"+j]};
- result = OpenLayers.Geometry.distanceToSegment(p, target);
- if(result.distance < tolerance) {
- if(point) {
- intersection = new OpenLayers.Geometry.Point(p.x, p.y);
- } else {
- intersection = true;
- }
- break outer;
- }
- }
- }
- }
- }
- return intersection;
-};
-
-/**
- * Function: OpenLayers.Geometry.distanceToSegment
- *
- * Parameters:
- * point - {Object} An object with x and y properties representing the
- * point coordinates.
- * segment - {Object} An object with x1, y1, x2, and y2 properties
- * representing endpoint coordinates.
- *
- * Returns:
- * {Object} An object with distance, along, x, and y properties. The distance
- * will be the shortest distance between the input point and segment.
- * The x and y properties represent the coordinates along the segment
- * where the shortest distance meets the segment. The along attribute
- * describes how far between the two segment points the given point is.
- */
-OpenLayers.Geometry.distanceToSegment = function(point, segment) {
- var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment);
- result.distance = Math.sqrt(result.distance);
- return result;
-};
-
-/**
- * Function: OpenLayers.Geometry.distanceSquaredToSegment
- *
- * Usually the distanceToSegment function should be used. This variant however
- * can be used for comparisons where the exact distance is not important.
- *
- * Parameters:
- * point - {Object} An object with x and y properties representing the
- * point coordinates.
- * segment - {Object} An object with x1, y1, x2, and y2 properties
- * representing endpoint coordinates.
- *
- * Returns:
- * {Object} An object with squared distance, along, x, and y properties.
- * The distance will be the shortest distance between the input point and
- * segment. The x and y properties represent the coordinates along the
- * segment where the shortest distance meets the segment. The along
- * attribute describes how far between the two segment points the given
- * point is.
- */
-OpenLayers.Geometry.distanceSquaredToSegment = function(point, segment) {
- var x0 = point.x;
- var y0 = point.y;
- var x1 = segment.x1;
- var y1 = segment.y1;
- var x2 = segment.x2;
- var y2 = segment.y2;
- var dx = x2 - x1;
- var dy = y2 - y1;
- var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) /
- (Math.pow(dx, 2) + Math.pow(dy, 2));
- var x, y;
- if(along <= 0.0) {
- x = x1;
- y = y1;
- } else if(along >= 1.0) {
- x = x2;
- y = y2;
- } else {
- x = x1 + along * dx;
- y = y1 + along * dy;
- }
- return {
- distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2),
- x: x, y: y,
- along: along
- };
-};
-/* ======================================================================
- OpenLayers/Geometry/Collection.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry.js
- */
-
-/**
- * Class: OpenLayers.Geometry.Collection
- * A Collection is exactly what it sounds like: A collection of different
- * Geometries. These are stored in the local parameter <components> (which
- * can be passed as a parameter to the constructor).
- *
- * As new geometries are added to the collection, they are NOT cloned.
- * When removing geometries, they need to be specified by reference (ie you
- * have to pass in the *exact* geometry to be removed).
- *
- * The <getArea> and <getLength> functions here merely iterate through
- * the components, summing their respective areas and lengths.
- *
- * Create a new instance with the <OpenLayers.Geometry.Collection> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, {
-
- /**
- * APIProperty: components
- * {Array(<OpenLayers.Geometry>)} The component parts of this geometry
- */
- components: null,
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: null,
-
- /**
- * Constructor: OpenLayers.Geometry.Collection
- * Creates a Geometry Collection -- a list of geoms.
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry>)} Optional array of geometries
- *
- */
- initialize: function (components) {
- OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
- this.components = [];
- if (components != null) {
- this.addComponents(components);
- }
- },
-
- /**
- * APIMethod: destroy
- * Destroy this geometry.
- */
- destroy: function () {
- this.components.length = 0;
- this.components = null;
- OpenLayers.Geometry.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: clone
- * Clone this geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.Collection>} An exact clone of this collection
- */
- clone: function() {
- var geometry = eval("new " + this.CLASS_NAME + "()");
- for(var i=0, len=this.components.length; i<len; i++) {
- geometry.addComponent(this.components[i].clone());
- }
-
- // catch any randomly tagged-on properties
- OpenLayers.Util.applyDefaults(geometry, this);
-
- return geometry;
- },
-
- /**
- * Method: getComponentsString
- * Get a string representing the components for this collection
- *
- * Returns:
- * {String} A string representation of the components of this geometry
- */
- getComponentsString: function(){
- var strings = [];
- for(var i=0, len=this.components.length; i<len; i++) {
- strings.push(this.components[i].toShortString());
- }
- return strings.join(",");
- },
-
- /**
- * APIMethod: calculateBounds
- * Recalculate the bounds by iterating through the components and
- * calling calling extendBounds() on each item.
- */
- calculateBounds: function() {
- this.bounds = null;
- var bounds = new OpenLayers.Bounds();
- var components = this.components;
- if (components) {
- for (var i=0, len=components.length; i<len; i++) {
- bounds.extend(components[i].getBounds());
- }
- }
- // to preserve old behavior, we only set bounds if non-null
- // in the future, we could add bounds.isEmpty()
- if (bounds.left != null && bounds.bottom != null &&
- bounds.right != null && bounds.top != null) {
- this.setBounds(bounds);
- }
- },
-
- /**
- * APIMethod: addComponents
- * Add components to this geometry.
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry>)} An array of geometries to add
- */
- addComponents: function(components){
- if(!(OpenLayers.Util.isArray(components))) {
- components = [components];
- }
- for(var i=0, len=components.length; i<len; i++) {
- this.addComponent(components[i]);
- }
- },
-
- /**
- * Method: addComponent
- * Add a new component (geometry) to the collection. If this.componentTypes
- * is set, then the component class name must be in the componentTypes array.
- *
- * The bounds cache is reset.
- *
- * Parameters:
- * component - {<OpenLayers.Geometry>} A geometry to add
- * index - {int} Optional index into the array to insert the component
- *
- * Returns:
- * {Boolean} The component geometry was successfully added
- */
- addComponent: function(component, index) {
- var added = false;
- if(component) {
- if(this.componentTypes == null ||
- (OpenLayers.Util.indexOf(this.componentTypes,
- component.CLASS_NAME) > -1)) {
-
- if(index != null && (index < this.components.length)) {
- var components1 = this.components.slice(0, index);
- var components2 = this.components.slice(index,
- this.components.length);
- components1.push(component);
- this.components = components1.concat(components2);
- } else {
- this.components.push(component);
- }
- component.parent = this;
- this.clearBounds();
- added = true;
- }
- }
- return added;
- },
-
- /**
- * APIMethod: removeComponents
- * Remove components from this geometry.
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry>)} The components to be removed
- *
- * Returns:
- * {Boolean} A component was removed.
- */
- removeComponents: function(components) {
- var removed = false;
-
- if(!(OpenLayers.Util.isArray(components))) {
- components = [components];
- }
- for(var i=components.length-1; i>=0; --i) {
- removed = this.removeComponent(components[i]) || removed;
- }
- return removed;
- },
-
- /**
- * Method: removeComponent
- * Remove a component from this geometry.
- *
- * Parameters:
- * component - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {Boolean} The component was removed.
- */
- removeComponent: function(component) {
-
- OpenLayers.Util.removeItem(this.components, component);
-
- // clearBounds() so that it gets recalculated on the next call
- // to this.getBounds();
- this.clearBounds();
- return true;
- },
-
- /**
- * APIMethod: getLength
- * Calculate the length of this geometry
- *
- * Returns:
- * {Float} The length of the geometry
- */
- getLength: function() {
- var length = 0.0;
- for (var i=0, len=this.components.length; i<len; i++) {
- length += this.components[i].getLength();
- }
- return length;
- },
-
- /**
- * APIMethod: getArea
- * Calculate the area of this geometry. Note how this function is overridden
- * in <OpenLayers.Geometry.Polygon>.
- *
- * Returns:
- * {Float} The area of the collection by summing its parts
- */
- getArea: function() {
- var area = 0.0;
- for (var i=0, len=this.components.length; i<len; i++) {
- area += this.components[i].getArea();
- }
- return area;
- },
-
- /**
- * APIMethod: getGeodesicArea
- * Calculate the approximate area of the polygon were it projected onto
- * the earth.
- *
- * Parameters:
- * projection - {<OpenLayers.Projection>} The spatial reference system
- * for the geometry coordinates. If not provided, Geographic/WGS84 is
- * assumed.
- *
- * Reference:
- * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
- * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
- * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
- *
- * Returns:
- * {float} The approximate geodesic area of the geometry in square meters.
- */
- getGeodesicArea: function(projection) {
- var area = 0.0;
- for(var i=0, len=this.components.length; i<len; i++) {
- area += this.components[i].getGeodesicArea(projection);
- }
- return area;
- },
-
- /**
- * APIMethod: getCentroid
- *
- * Compute the centroid for this geometry collection.
- *
- * Parameters:
- * weighted - {Boolean} Perform the getCentroid computation recursively,
- * returning an area weighted average of all geometries in this collection.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} The centroid of the collection
- */
- getCentroid: function(weighted) {
- if (!weighted) {
- return this.components.length && this.components[0].getCentroid();
- }
- var len = this.components.length;
- if (!len) {
- return false;
- }
-
- var areas = [];
- var centroids = [];
- var areaSum = 0;
- var minArea = Number.MAX_VALUE;
- var component;
- for (var i=0; i<len; ++i) {
- component = this.components[i];
- var area = component.getArea();
- var centroid = component.getCentroid(true);
- if (isNaN(area) || isNaN(centroid.x) || isNaN(centroid.y)) {
- continue;
- }
- areas.push(area);
- areaSum += area;
- minArea = (area < minArea && area > 0) ? area : minArea;
- centroids.push(centroid);
- }
- len = areas.length;
- if (areaSum === 0) {
- // all the components in this collection have 0 area
- // probably a collection of points -- weight all the points the same
- for (var i=0; i<len; ++i) {
- areas[i] = 1;
- }
- areaSum = areas.length;
- } else {
- // normalize all the areas where the smallest area will get
- // a value of 1
- for (var i=0; i<len; ++i) {
- areas[i] /= minArea;
- }
- areaSum /= minArea;
- }
-
- var xSum = 0, ySum = 0, centroid, area;
- for (var i=0; i<len; ++i) {
- centroid = centroids[i];
- area = areas[i];
- xSum += centroid.x * area;
- ySum += centroid.y * area;
- }
-
- return new OpenLayers.Geometry.Point(xSum/areaSum, ySum/areaSum);
- },
-
- /**
- * APIMethod: getGeodesicLength
- * Calculate the approximate length of the geometry were it projected onto
- * the earth.
- *
- * projection - {<OpenLayers.Projection>} The spatial reference system
- * for the geometry coordinates. If not provided, Geographic/WGS84 is
- * assumed.
- *
- * Returns:
- * {Float} The appoximate geodesic length of the geometry in meters.
- */
- getGeodesicLength: function(projection) {
- var length = 0.0;
- for(var i=0, len=this.components.length; i<len; i++) {
- length += this.components[i].getGeodesicLength(projection);
- }
- return length;
- },
-
- /**
- * APIMethod: move
- * Moves a geometry by the given displacement along positive x and y axes.
- * This modifies the position of the geometry and clears the cached
- * bounds.
- *
- * Parameters:
- * x - {Float} Distance to move geometry in positive x direction.
- * y - {Float} Distance to move geometry in positive y direction.
- */
- move: function(x, y) {
- for(var i=0, len=this.components.length; i<len; i++) {
- this.components[i].move(x, y);
- }
- },
-
- /**
- * APIMethod: rotate
- * Rotate a geometry around some origin
- *
- * Parameters:
- * angle - {Float} Rotation angle in degrees (measured counterclockwise
- * from the positive x-axis)
- * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
- */
- rotate: function(angle, origin) {
- for(var i=0, len=this.components.length; i<len; ++i) {
- this.components[i].rotate(angle, origin);
- }
- },
-
- /**
- * APIMethod: resize
- * Resize a geometry relative to some origin. Use this method to apply
- * a uniform scaling to a geometry.
- *
- * Parameters:
- * scale - {Float} Factor by which to scale the geometry. A scale of 2
- * doubles the size of the geometry in each dimension
- * (lines, for example, will be twice as long, and polygons
- * will have four times the area).
- * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
- * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1.
- *
- * Returns:
- * {<OpenLayers.Geometry>} - The current geometry.
- */
- resize: function(scale, origin, ratio) {
- for(var i=0; i<this.components.length; ++i) {
- this.components[i].resize(scale, origin, ratio);
- }
- return this;
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and y1 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var details = edge && options && options.details;
- var result, best, distance;
- var min = Number.POSITIVE_INFINITY;
- for(var i=0, len=this.components.length; i<len; ++i) {
- result = this.components[i].distanceTo(geometry, options);
- distance = details ? result.distance : result;
- if(distance < min) {
- min = distance;
- best = result;
- if(min == 0) {
- break;
- }
- }
- }
- return best;
- },
-
- /**
- * APIMethod: equals
- * Determine whether another geometry is equivalent to this one. Geometries
- * are considered equivalent if all components have the same coordinates.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The geometry to test.
- *
- * Returns:
- * {Boolean} The supplied geometry is equivalent to this geometry.
- */
- equals: function(geometry) {
- var equivalent = true;
- if(!geometry || !geometry.CLASS_NAME ||
- (this.CLASS_NAME != geometry.CLASS_NAME)) {
- equivalent = false;
- } else if(!(OpenLayers.Util.isArray(geometry.components)) ||
- (geometry.components.length != this.components.length)) {
- equivalent = false;
- } else {
- for(var i=0, len=this.components.length; i<len; ++i) {
- if(!this.components[i].equals(geometry.components[i])) {
- equivalent = false;
- break;
- }
- }
- }
- return equivalent;
- },
-
- /**
- * APIMethod: transform
- * Reproject the components geometry from source to dest.
- *
- * Parameters:
- * source - {<OpenLayers.Projection>}
- * dest - {<OpenLayers.Projection>}
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- transform: function(source, dest) {
- if (source && dest) {
- for (var i=0, len=this.components.length; i<len; i++) {
- var component = this.components[i];
- component.transform(source, dest);
- }
- this.bounds = null;
- }
- return this;
- },
-
- /**
- * APIMethod: intersects
- * Determine if the input geometry intersects this one.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} Any type of geometry.
- *
- * Returns:
- * {Boolean} The input geometry intersects this one.
- */
- intersects: function(geometry) {
- var intersect = false;
- for(var i=0, len=this.components.length; i<len; ++ i) {
- intersect = geometry.intersects(this.components[i]);
- if(intersect) {
- break;
- }
- }
- return intersect;
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- var vertices = [];
- for(var i=0, len=this.components.length; i<len; ++i) {
- Array.prototype.push.apply(
- vertices, this.components[i].getVertices(nodes)
- );
- }
- return vertices;
- },
-
-
- CLASS_NAME: "OpenLayers.Geometry.Collection"
-});
-/* ======================================================================
- OpenLayers/Geometry/Point.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry.js
- */
-
-/**
- * Class: OpenLayers.Geometry.Point
- * Point geometry class.
- *
- * Inherits from:
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.Point = OpenLayers.Class(OpenLayers.Geometry, {
-
- /**
- * APIProperty: x
- * {float}
- */
- x: null,
-
- /**
- * APIProperty: y
- * {float}
- */
- y: null,
-
- /**
- * Constructor: OpenLayers.Geometry.Point
- * Construct a point geometry.
- *
- * Parameters:
- * x - {float}
- * y - {float}
- *
- */
- initialize: function(x, y) {
- OpenLayers.Geometry.prototype.initialize.apply(this, arguments);
-
- this.x = parseFloat(x);
- this.y = parseFloat(y);
- },
-
- /**
- * APIMethod: clone
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} An exact clone of this OpenLayers.Geometry.Point
- */
- clone: function(obj) {
- if (obj == null) {
- obj = new OpenLayers.Geometry.Point(this.x, this.y);
- }
-
- // catch any randomly tagged-on properties
- OpenLayers.Util.applyDefaults(obj, this);
-
- return obj;
- },
-
- /**
- * Method: calculateBounds
- * Create a new Bounds based on the lon/lat
- */
- calculateBounds: function () {
- this.bounds = new OpenLayers.Bounds(this.x, this.y,
- this.x, this.y);
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and x2 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var details = edge && options && options.details;
- var distance, x0, y0, x1, y1, result;
- if(geometry instanceof OpenLayers.Geometry.Point) {
- x0 = this.x;
- y0 = this.y;
- x1 = geometry.x;
- y1 = geometry.y;
- distance = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
- result = !details ?
- distance : {x0: x0, y0: y0, x1: x1, y1: y1, distance: distance};
- } else {
- result = geometry.distanceTo(this, options);
- if(details) {
- // switch coord order since this geom is target
- result = {
- x0: result.x1, y0: result.y1,
- x1: result.x0, y1: result.y0,
- distance: result.distance
- };
- }
- }
- return result;
- },
-
- /**
- * APIMethod: equals
- * Determine whether another geometry is equivalent to this one. Geometries
- * are considered equivalent if all components have the same coordinates.
- *
- * Parameters:
- * geom - {<OpenLayers.Geometry.Point>} The geometry to test.
- *
- * Returns:
- * {Boolean} The supplied geometry is equivalent to this geometry.
- */
- equals: function(geom) {
- var equals = false;
- if (geom != null) {
- equals = ((this.x == geom.x && this.y == geom.y) ||
- (isNaN(this.x) && isNaN(this.y) && isNaN(geom.x) && isNaN(geom.y)));
- }
- return equals;
- },
-
- /**
- * Method: toShortString
- *
- * Returns:
- * {String} Shortened String representation of Point object.
- * (ex. <i>"5, 42"</i>)
- */
- toShortString: function() {
- return (this.x + ", " + this.y);
- },
-
- /**
- * APIMethod: move
- * Moves a geometry by the given displacement along positive x and y axes.
- * This modifies the position of the geometry and clears the cached
- * bounds.
- *
- * Parameters:
- * x - {Float} Distance to move geometry in positive x direction.
- * y - {Float} Distance to move geometry in positive y direction.
- */
- move: function(x, y) {
- this.x = this.x + x;
- this.y = this.y + y;
- this.clearBounds();
- },
-
- /**
- * APIMethod: rotate
- * Rotate a point around another.
- *
- * Parameters:
- * angle - {Float} Rotation angle in degrees (measured counterclockwise
- * from the positive x-axis)
- * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
- */
- rotate: function(angle, origin) {
- angle *= Math.PI / 180;
- var radius = this.distanceTo(origin);
- var theta = angle + Math.atan2(this.y - origin.y, this.x - origin.x);
- this.x = origin.x + (radius * Math.cos(theta));
- this.y = origin.y + (radius * Math.sin(theta));
- this.clearBounds();
- },
-
- /**
- * APIMethod: getCentroid
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} The centroid of the collection
- */
- getCentroid: function() {
- return new OpenLayers.Geometry.Point(this.x, this.y);
- },
-
- /**
- * APIMethod: resize
- * Resize a point relative to some origin. For points, this has the effect
- * of scaling a vector (from the origin to the point). This method is
- * more useful on geometry collection subclasses.
- *
- * Parameters:
- * scale - {Float} Ratio of the new distance from the origin to the old
- * distance from the origin. A scale of 2 doubles the
- * distance between the point and origin.
- * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
- * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1.
- *
- * Returns:
- * {<OpenLayers.Geometry>} - The current geometry.
- */
- resize: function(scale, origin, ratio) {
- ratio = (ratio == undefined) ? 1 : ratio;
- this.x = origin.x + (scale * ratio * (this.x - origin.x));
- this.y = origin.y + (scale * (this.y - origin.y));
- this.clearBounds();
- return this;
- },
-
- /**
- * APIMethod: intersects
- * Determine if the input geometry intersects this one.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} Any type of geometry.
- *
- * Returns:
- * {Boolean} The input geometry intersects this one.
- */
- intersects: function(geometry) {
- var intersect = false;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- intersect = this.equals(geometry);
- } else {
- intersect = geometry.intersects(this);
- }
- return intersect;
- },
-
- /**
- * APIMethod: transform
- * Translate the x,y properties of the point from source to dest.
- *
- * Parameters:
- * source - {<OpenLayers.Projection>}
- * dest - {<OpenLayers.Projection>}
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- transform: function(source, dest) {
- if ((source && dest)) {
- OpenLayers.Projection.transform(
- this, source, dest);
- this.bounds = null;
- }
- return this;
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- return [this];
- },
-
- CLASS_NAME: "OpenLayers.Geometry.Point"
-});
-/* ======================================================================
- OpenLayers/Geometry/MultiPoint.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Geometry/Point.js
- */
-
-/**
- * Class: OpenLayers.Geometry.MultiPoint
- * MultiPoint is a collection of Points. Create a new instance with the
- * <OpenLayers.Geometry.MultiPoint> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Collection>
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.MultiPoint = OpenLayers.Class(
- OpenLayers.Geometry.Collection, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.Point"],
-
- /**
- * Constructor: OpenLayers.Geometry.MultiPoint
- * Create a new MultiPoint Geometry
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.Point>)}
- *
- * Returns:
- * {<OpenLayers.Geometry.MultiPoint>}
- */
-
- /**
- * APIMethod: addPoint
- * Wrapper for <OpenLayers.Geometry.Collection.addComponent>
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>} Point to be added
- * index - {Integer} Optional index
- */
- addPoint: function(point, index) {
- this.addComponent(point, index);
- },
-
- /**
- * APIMethod: removePoint
- * Wrapper for <OpenLayers.Geometry.Collection.removeComponent>
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>} Point to be removed
- */
- removePoint: function(point){
- this.removeComponent(point);
- },
-
- CLASS_NAME: "OpenLayers.Geometry.MultiPoint"
-});
-/* ======================================================================
- OpenLayers/Geometry/Curve.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/MultiPoint.js
- */
-
-/**
- * Class: OpenLayers.Geometry.Curve
- * A Curve is a MultiPoint, whose points are assumed to be connected. To
- * this end, we provide a "getLength()" function, which iterates through
- * the points, summing the distances between them.
- *
- * Inherits:
- * - <OpenLayers.Geometry.MultiPoint>
- */
-OpenLayers.Geometry.Curve = OpenLayers.Class(OpenLayers.Geometry.MultiPoint, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null
- * value means the component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.Point"],
-
- /**
- * Constructor: OpenLayers.Geometry.Curve
- *
- * Parameters:
- * point - {Array(<OpenLayers.Geometry.Point>)}
- */
-
- /**
- * APIMethod: getLength
- *
- * Returns:
- * {Float} The length of the curve
- */
- getLength: function() {
- var length = 0.0;
- if ( this.components && (this.components.length > 1)) {
- for(var i=1, len=this.components.length; i<len; i++) {
- length += this.components[i-1].distanceTo(this.components[i]);
- }
- }
- return length;
- },
-
- /**
- * APIMethod: getGeodesicLength
- * Calculate the approximate length of the geometry were it projected onto
- * the earth.
- *
- * projection - {<OpenLayers.Projection>} The spatial reference system
- * for the geometry coordinates. If not provided, Geographic/WGS84 is
- * assumed.
- *
- * Returns:
- * {Float} The appoximate geodesic length of the geometry in meters.
- */
- getGeodesicLength: function(projection) {
- var geom = this; // so we can work with a clone if needed
- if(projection) {
- var gg = new OpenLayers.Projection("EPSG:4326");
- if(!gg.equals(projection)) {
- geom = this.clone().transform(projection, gg);
- }
- }
- var length = 0.0;
- if(geom.components && (geom.components.length > 1)) {
- var p1, p2;
- for(var i=1, len=geom.components.length; i<len; i++) {
- p1 = geom.components[i-1];
- p2 = geom.components[i];
- // this returns km and requires lon/lat properties
- length += OpenLayers.Util.distVincenty(
- {lon: p1.x, lat: p1.y}, {lon: p2.x, lat: p2.y}
- );
- }
- }
- // convert to m
- return length * 1000;
- },
-
- CLASS_NAME: "OpenLayers.Geometry.Curve"
-});
-/* ======================================================================
- OpenLayers/Geometry/LineString.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Curve.js
- */
-
-/**
- * Class: OpenLayers.Geometry.LineString
- * A LineString is a Curve which, once two points have been added to it, can
- * never be less than two points long.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Curve>
- */
-OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
-
- /**
- * Constructor: OpenLayers.Geometry.LineString
- * Create a new LineString geometry
- *
- * Parameters:
- * points - {Array(<OpenLayers.Geometry.Point>)} An array of points used to
- * generate the linestring
- *
- */
-
- /**
- * APIMethod: removeComponent
- * Only allows removal of a point if there are three or more points in
- * the linestring. (otherwise the result would be just a single point)
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>} The point to be removed
- *
- * Returns:
- * {Boolean} The component was removed.
- */
- removeComponent: function(point) {
- var removed = this.components && (this.components.length > 2);
- if (removed) {
- OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
- arguments);
- }
- return removed;
- },
-
- /**
- * APIMethod: intersects
- * Test for instersection between two geometries. This is a cheapo
- * implementation of the Bently-Ottmann algorigithm. It doesn't
- * really keep track of a sweep line data structure. It is closer
- * to the brute force method, except that segments are sorted and
- * potential intersections are only calculated when bounding boxes
- * intersect.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {Boolean} The input geometry intersects this geometry.
- */
- intersects: function(geometry) {
- var intersect = false;
- var type = geometry.CLASS_NAME;
- if(type == "OpenLayers.Geometry.LineString" ||
- type == "OpenLayers.Geometry.LinearRing" ||
- type == "OpenLayers.Geometry.Point") {
- var segs1 = this.getSortedSegments();
- var segs2;
- if(type == "OpenLayers.Geometry.Point") {
- segs2 = [{
- x1: geometry.x, y1: geometry.y,
- x2: geometry.x, y2: geometry.y
- }];
- } else {
- segs2 = geometry.getSortedSegments();
- }
- var seg1, seg1x1, seg1x2, seg1y1, seg1y2,
- seg2, seg2y1, seg2y2;
- // sweep right
- outer: for(var i=0, len=segs1.length; i<len; ++i) {
- seg1 = segs1[i];
- seg1x1 = seg1.x1;
- seg1x2 = seg1.x2;
- seg1y1 = seg1.y1;
- seg1y2 = seg1.y2;
- inner: for(var j=0, jlen=segs2.length; j<jlen; ++j) {
- seg2 = segs2[j];
- if(seg2.x1 > seg1x2) {
- // seg1 still left of seg2
- break;
- }
- if(seg2.x2 < seg1x1) {
- // seg2 still left of seg1
- continue;
- }
- seg2y1 = seg2.y1;
- seg2y2 = seg2.y2;
- if(Math.min(seg2y1, seg2y2) > Math.max(seg1y1, seg1y2)) {
- // seg2 above seg1
- continue;
- }
- if(Math.max(seg2y1, seg2y2) < Math.min(seg1y1, seg1y2)) {
- // seg2 below seg1
- continue;
- }
- if(OpenLayers.Geometry.segmentsIntersect(seg1, seg2)) {
- intersect = true;
- break outer;
- }
- }
- }
- } else {
- intersect = geometry.intersects(this);
- }
- return intersect;
- },
-
- /**
- * Method: getSortedSegments
- *
- * Returns:
- * {Array} An array of segment objects. Segment objects have properties
- * x1, y1, x2, and y2. The start point is represented by x1 and y1.
- * The end point is represented by x2 and y2. Start and end are
- * ordered so that x1 < x2.
- */
- getSortedSegments: function() {
- var numSeg = this.components.length - 1;
- var segments = new Array(numSeg), point1, point2;
- for(var i=0; i<numSeg; ++i) {
- point1 = this.components[i];
- point2 = this.components[i + 1];
- if(point1.x < point2.x) {
- segments[i] = {
- x1: point1.x,
- y1: point1.y,
- x2: point2.x,
- y2: point2.y
- };
- } else {
- segments[i] = {
- x1: point2.x,
- y1: point2.y,
- x2: point1.x,
- y2: point1.y
- };
- }
- }
- // more efficient to define this somewhere static
- function byX1(seg1, seg2) {
- return seg1.x1 - seg2.x1;
- }
- return segments.sort(byX1);
- },
-
- /**
- * Method: splitWithSegment
- * Split this geometry with the given segment.
- *
- * Parameters:
- * seg - {Object} An object with x1, y1, x2, and y2 properties referencing
- * segment endpoint coordinates.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source segment must be within the
- * tolerance distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of one of the source segment's
- * endpoints will be assumed to occur at the endpoint.
- *
- * Returns:
- * {Object} An object with *lines* and *points* properties. If the given
- * segment intersects this linestring, the lines array will reference
- * geometries that result from the split. The points array will contain
- * all intersection points. Intersection points are sorted along the
- * segment (in order from x1,y1 to x2,y2).
- */
- splitWithSegment: function(seg, options) {
- var edge = !(options && options.edge === false);
- var tolerance = options && options.tolerance;
- var lines = [];
- var verts = this.getVertices();
- var points = [];
- var intersections = [];
- var split = false;
- var vert1, vert2, point;
- var node, vertex, target;
- var interOptions = {point: true, tolerance: tolerance};
- var result = null;
- for(var i=0, stop=verts.length-2; i<=stop; ++i) {
- vert1 = verts[i];
- points.push(vert1.clone());
- vert2 = verts[i+1];
- target = {x1: vert1.x, y1: vert1.y, x2: vert2.x, y2: vert2.y};
- point = OpenLayers.Geometry.segmentsIntersect(
- seg, target, interOptions
- );
- if(point instanceof OpenLayers.Geometry.Point) {
- if((point.x === seg.x1 && point.y === seg.y1) ||
- (point.x === seg.x2 && point.y === seg.y2) ||
- point.equals(vert1) || point.equals(vert2)) {
- vertex = true;
- } else {
- vertex = false;
- }
- if(vertex || edge) {
- // push intersections different than the previous
- if(!point.equals(intersections[intersections.length-1])) {
- intersections.push(point.clone());
- }
- if(i === 0) {
- if(point.equals(vert1)) {
- continue;
- }
- }
- if(point.equals(vert2)) {
- continue;
- }
- split = true;
- if(!point.equals(vert1)) {
- points.push(point);
- }
- lines.push(new OpenLayers.Geometry.LineString(points));
- points = [point.clone()];
- }
- }
- }
- if(split) {
- points.push(vert2.clone());
- lines.push(new OpenLayers.Geometry.LineString(points));
- }
- if(intersections.length > 0) {
- // sort intersections along segment
- var xDir = seg.x1 < seg.x2 ? 1 : -1;
- var yDir = seg.y1 < seg.y2 ? 1 : -1;
- result = {
- lines: lines,
- points: intersections.sort(function(p1, p2) {
- return (xDir * p1.x - xDir * p2.x) || (yDir * p1.y - yDir * p2.y);
- })
- };
- }
- return result;
- },
-
- /**
- * Method: split
- * Use this geometry (the source) to attempt to split a target geometry.
- *
- * Parameters:
- * target - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- split: function(target, options) {
- var results = null;
- var mutual = options && options.mutual;
- var sourceSplit, targetSplit, sourceParts, targetParts;
- if(target instanceof OpenLayers.Geometry.LineString) {
- var verts = this.getVertices();
- var vert1, vert2, seg, splits, lines, point;
- var points = [];
- sourceParts = [];
- for(var i=0, stop=verts.length-2; i<=stop; ++i) {
- vert1 = verts[i];
- vert2 = verts[i+1];
- seg = {
- x1: vert1.x, y1: vert1.y,
- x2: vert2.x, y2: vert2.y
- };
- targetParts = targetParts || [target];
- if(mutual) {
- points.push(vert1.clone());
- }
- for(var j=0; j<targetParts.length; ++j) {
- splits = targetParts[j].splitWithSegment(seg, options);
- if(splits) {
- // splice in new features
- lines = splits.lines;
- if(lines.length > 0) {
- lines.unshift(j, 1);
- Array.prototype.splice.apply(targetParts, lines);
- j += lines.length - 2;
- }
- if(mutual) {
- for(var k=0, len=splits.points.length; k<len; ++k) {
- point = splits.points[k];
- if(!point.equals(vert1)) {
- points.push(point);
- sourceParts.push(new OpenLayers.Geometry.LineString(points));
- if(point.equals(vert2)) {
- points = [];
- } else {
- points = [point.clone()];
- }
- }
- }
- }
- }
- }
- }
- if(mutual && sourceParts.length > 0 && points.length > 0) {
- points.push(vert2.clone());
- sourceParts.push(new OpenLayers.Geometry.LineString(points));
- }
- } else {
- results = target.splitWith(this, options);
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetSplit || sourceSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- /**
- * Method: splitWith
- * Split this geometry (the target) with the given geometry (the source).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} A geometry used to split this
- * geometry (the source).
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- splitWith: function(geometry, options) {
- return geometry.split(this, options);
-
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- var vertices;
- if(nodes === true) {
- vertices = [
- this.components[0],
- this.components[this.components.length-1]
- ];
- } else if (nodes === false) {
- vertices = this.components.slice(1, this.components.length-1);
- } else {
- vertices = this.components.slice();
- }
- return vertices;
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and x2 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var details = edge && options && options.details;
- var result, best = {};
- var min = Number.POSITIVE_INFINITY;
- if(geometry instanceof OpenLayers.Geometry.Point) {
- var segs = this.getSortedSegments();
- var x = geometry.x;
- var y = geometry.y;
- var seg;
- for(var i=0, len=segs.length; i<len; ++i) {
- seg = segs[i];
- result = OpenLayers.Geometry.distanceToSegment(geometry, seg);
- if(result.distance < min) {
- min = result.distance;
- best = result;
- if(min === 0) {
- break;
- }
- } else {
- // if distance increases and we cross y0 to the right of x0, no need to keep looking.
- if(seg.x2 > x && ((y > seg.y1 && y < seg.y2) || (y < seg.y1 && y > seg.y2))) {
- break;
- }
- }
- }
- if(details) {
- best = {
- distance: best.distance,
- x0: best.x, y0: best.y,
- x1: x, y1: y
- };
- } else {
- best = best.distance;
- }
- } else if(geometry instanceof OpenLayers.Geometry.LineString) {
- var segs0 = this.getSortedSegments();
- var segs1 = geometry.getSortedSegments();
- var seg0, seg1, intersection, x0, y0;
- var len1 = segs1.length;
- var interOptions = {point: true};
- outer: for(var i=0, len=segs0.length; i<len; ++i) {
- seg0 = segs0[i];
- x0 = seg0.x1;
- y0 = seg0.y1;
- for(var j=0; j<len1; ++j) {
- seg1 = segs1[j];
- intersection = OpenLayers.Geometry.segmentsIntersect(seg0, seg1, interOptions);
- if(intersection) {
- min = 0;
- best = {
- distance: 0,
- x0: intersection.x, y0: intersection.y,
- x1: intersection.x, y1: intersection.y
- };
- break outer;
- } else {
- result = OpenLayers.Geometry.distanceToSegment({x: x0, y: y0}, seg1);
- if(result.distance < min) {
- min = result.distance;
- best = {
- distance: min,
- x0: x0, y0: y0,
- x1: result.x, y1: result.y
- };
- }
- }
- }
- }
- if(!details) {
- best = best.distance;
- }
- if(min !== 0) {
- // check the final vertex in this line's sorted segments
- if(seg0) {
- result = geometry.distanceTo(
- new OpenLayers.Geometry.Point(seg0.x2, seg0.y2),
- options
- );
- var dist = details ? result.distance : result;
- if(dist < min) {
- if(details) {
- best = {
- distance: min,
- x0: result.x1, y0: result.y1,
- x1: result.x0, y1: result.y0
- };
- } else {
- best = dist;
- }
- }
- }
- }
- } else {
- best = geometry.distanceTo(this, options);
- // swap since target comes from this line
- if(details) {
- best = {
- distance: best.distance,
- x0: best.x1, y0: best.y1,
- x1: best.x0, y1: best.y0
- };
- }
- }
- return best;
- },
-
- /**
- * APIMethod: simplify
- * This function will return a simplified LineString.
- * Simplification is based on the Douglas-Peucker algorithm.
- *
- *
- * Parameters:
- * tolerance - {number} threshhold for simplification in map units
- *
- * Returns:
- * {OpenLayers.Geometry.LineString} the simplified LineString
- */
- simplify: function(tolerance){
- if (this && this !== null) {
- var points = this.getVertices();
- if (points.length < 3) {
- return this;
- }
-
- var compareNumbers = function(a, b){
- return (a-b);
- };
-
- /**
- * Private function doing the Douglas-Peucker reduction
- */
- var douglasPeuckerReduction = function(points, firstPoint, lastPoint, tolerance){
- var maxDistance = 0;
- var indexFarthest = 0;
-
- for (var index = firstPoint, distance; index < lastPoint; index++) {
- distance = perpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
- if (distance > maxDistance) {
- maxDistance = distance;
- indexFarthest = index;
- }
- }
-
- if (maxDistance > tolerance && indexFarthest != firstPoint) {
- //Add the largest point that exceeds the tolerance
- pointIndexsToKeep.push(indexFarthest);
- douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance);
- douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance);
- }
- };
-
- /**
- * Private function calculating the perpendicular distance
- * TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower
- */
- var perpendicularDistance = function(point1, point2, point){
- //Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle
- //Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle*
- //Area = .5*Base*H *Solve for height
- //Height = Area/.5/Base
-
- var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y));
- var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
- var height = area / bottom * 2;
-
- return height;
- };
-
- var firstPoint = 0;
- var lastPoint = points.length - 1;
- var pointIndexsToKeep = [];
-
- //Add the first and last index to the keepers
- pointIndexsToKeep.push(firstPoint);
- pointIndexsToKeep.push(lastPoint);
-
- //The first and the last point cannot be the same
- while (points[firstPoint].equals(points[lastPoint])) {
- lastPoint--;
- //Addition: the first point not equal to first point in the LineString is kept as well
- pointIndexsToKeep.push(lastPoint);
- }
-
- douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance);
- var returnPoints = [];
- pointIndexsToKeep.sort(compareNumbers);
- for (var index = 0; index < pointIndexsToKeep.length; index++) {
- returnPoints.push(points[pointIndexsToKeep[index]]);
- }
- return new OpenLayers.Geometry.LineString(returnPoints);
-
- }
- else {
- return this;
- }
- },
-
- CLASS_NAME: "OpenLayers.Geometry.LineString"
-});
-/* ======================================================================
- OpenLayers/Geometry/LinearRing.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/LineString.js
- */
-
-/**
- * Class: OpenLayers.Geometry.LinearRing
- *
- * A Linear Ring is a special LineString which is closed. It closes itself
- * automatically on every addPoint/removePoint by adding a copy of the first
- * point as the last point.
- *
- * Also, as it is the first in the line family to close itself, a getArea()
- * function is defined to calculate the enclosed area of the linearRing
- *
- * Inherits:
- * - <OpenLayers.Geometry.LineString>
- */
-OpenLayers.Geometry.LinearRing = OpenLayers.Class(
- OpenLayers.Geometry.LineString, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null
- * value means the component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.Point"],
-
- /**
- * Constructor: OpenLayers.Geometry.LinearRing
- * Linear rings are constructed with an array of points. This array
- * can represent a closed or open ring. If the ring is open (the last
- * point does not equal the first point), the constructor will close
- * the ring. If the ring is already closed (the last point does equal
- * the first point), it will be left closed.
- *
- * Parameters:
- * points - {Array(<OpenLayers.Geometry.Point>)} points
- */
-
- /**
- * APIMethod: addComponent
- * Adds a point to geometry components. If the point is to be added to
- * the end of the components array and it is the same as the last point
- * already in that array, the duplicate point is not added. This has
- * the effect of closing the ring if it is not already closed, and
- * doing the right thing if it is already closed. This behavior can
- * be overridden by calling the method with a non-null index as the
- * second argument.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- * index - {Integer} Index into the array to insert the component
- *
- * Returns:
- * {Boolean} Was the Point successfully added?
- */
- addComponent: function(point, index) {
- var added = false;
-
- //remove last point
- var lastPoint = this.components.pop();
-
- // given an index, add the point
- // without an index only add non-duplicate points
- if(index != null || !point.equals(lastPoint)) {
- added = OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
- arguments);
- }
-
- //append copy of first point
- var firstPoint = this.components[0];
- OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
- [firstPoint]);
-
- return added;
- },
-
- /**
- * APIMethod: removeComponent
- * Removes a point from geometry components.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {Boolean} The component was removed.
- */
- removeComponent: function(point) {
- var removed = this.components && (this.components.length > 3);
- if (removed) {
- //remove last point
- this.components.pop();
-
- //remove our point
- OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
- arguments);
- //append copy of first point
- var firstPoint = this.components[0];
- OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,
- [firstPoint]);
- }
- return removed;
- },
-
- /**
- * APIMethod: move
- * Moves a geometry by the given displacement along positive x and y axes.
- * This modifies the position of the geometry and clears the cached
- * bounds.
- *
- * Parameters:
- * x - {Float} Distance to move geometry in positive x direction.
- * y - {Float} Distance to move geometry in positive y direction.
- */
- move: function(x, y) {
- for(var i = 0, len=this.components.length; i<len - 1; i++) {
- this.components[i].move(x, y);
- }
- },
-
- /**
- * APIMethod: rotate
- * Rotate a geometry around some origin
- *
- * Parameters:
- * angle - {Float} Rotation angle in degrees (measured counterclockwise
- * from the positive x-axis)
- * origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
- */
- rotate: function(angle, origin) {
- for(var i=0, len=this.components.length; i<len - 1; ++i) {
- this.components[i].rotate(angle, origin);
- }
- },
-
- /**
- * APIMethod: resize
- * Resize a geometry relative to some origin. Use this method to apply
- * a uniform scaling to a geometry.
- *
- * Parameters:
- * scale - {Float} Factor by which to scale the geometry. A scale of 2
- * doubles the size of the geometry in each dimension
- * (lines, for example, will be twice as long, and polygons
- * will have four times the area).
- * origin - {<OpenLayers.Geometry.Point>} Point of origin for resizing
- * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1.
- *
- * Returns:
- * {<OpenLayers.Geometry>} - The current geometry.
- */
- resize: function(scale, origin, ratio) {
- for(var i=0, len=this.components.length; i<len - 1; ++i) {
- this.components[i].resize(scale, origin, ratio);
- }
- return this;
- },
-
- /**
- * APIMethod: transform
- * Reproject the components geometry from source to dest.
- *
- * Parameters:
- * source - {<OpenLayers.Projection>}
- * dest - {<OpenLayers.Projection>}
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- transform: function(source, dest) {
- if (source && dest) {
- for (var i=0, len=this.components.length; i<len - 1; i++) {
- var component = this.components[i];
- component.transform(source, dest);
- }
- this.bounds = null;
- }
- return this;
- },
-
- /**
- * APIMethod: getCentroid
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} The centroid of the collection
- */
- getCentroid: function() {
- if (this.components) {
- var len = this.components.length;
- if (len > 0 && len <= 2) {
- return this.components[0].clone();
- } else if (len > 2) {
- var sumX = 0.0;
- var sumY = 0.0;
- var x0 = this.components[0].x;
- var y0 = this.components[0].y;
- var area = -1 * this.getArea();
- if (area != 0) {
- for (var i = 0; i < len - 1; i++) {
- var b = this.components[i];
- var c = this.components[i+1];
- sumX += (b.x + c.x - 2 * x0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0));
- sumY += (b.y + c.y - 2 * y0) * ((b.x - x0) * (c.y - y0) - (c.x - x0) * (b.y - y0));
- }
- var x = x0 + sumX / (6 * area);
- var y = y0 + sumY / (6 * area);
- } else {
- for (var i = 0; i < len - 1; i++) {
- sumX += this.components[i].x;
- sumY += this.components[i].y;
- }
- var x = sumX / (len - 1);
- var y = sumY / (len - 1);
- }
- return new OpenLayers.Geometry.Point(x, y);
- } else {
- return null;
- }
- }
- },
-
- /**
- * APIMethod: getArea
- * Note - The area is positive if the ring is oriented CW, otherwise
- * it will be negative.
- *
- * Returns:
- * {Float} The signed area for a ring.
- */
- getArea: function() {
- var area = 0.0;
- if ( this.components && (this.components.length > 2)) {
- var sum = 0.0;
- for (var i=0, len=this.components.length; i<len - 1; i++) {
- var b = this.components[i];
- var c = this.components[i+1];
- sum += (b.x + c.x) * (c.y - b.y);
- }
- area = - sum / 2.0;
- }
- return area;
- },
-
- /**
- * APIMethod: getGeodesicArea
- * Calculate the approximate area of the polygon were it projected onto
- * the earth. Note that this area will be positive if ring is oriented
- * clockwise, otherwise it will be negative.
- *
- * Parameters:
- * projection - {<OpenLayers.Projection>} The spatial reference system
- * for the geometry coordinates. If not provided, Geographic/WGS84 is
- * assumed.
- *
- * Reference:
- * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
- * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
- * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
- *
- * Returns:
- * {float} The approximate signed geodesic area of the polygon in square
- * meters.
- */
- getGeodesicArea: function(projection) {
- var ring = this; // so we can work with a clone if needed
- if(projection) {
- var gg = new OpenLayers.Projection("EPSG:4326");
- if(!gg.equals(projection)) {
- ring = this.clone().transform(projection, gg);
- }
- }
- var area = 0.0;
- var len = ring.components && ring.components.length;
- if(len > 2) {
- var p1, p2;
- for(var i=0; i<len-1; i++) {
- p1 = ring.components[i];
- p2 = ring.components[i+1];
- area += OpenLayers.Util.rad(p2.x - p1.x) *
- (2 + Math.sin(OpenLayers.Util.rad(p1.y)) +
- Math.sin(OpenLayers.Util.rad(p2.y)));
- }
- area = area * 6378137.0 * 6378137.0 / 2.0;
- }
- return area;
- },
-
- /**
- * Method: containsPoint
- * Test if a point is inside a linear ring. For the case where a point
- * is coincident with a linear ring edge, returns 1. Otherwise,
- * returns boolean.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {Boolean | Number} The point is inside the linear ring. Returns 1 if
- * the point is coincident with an edge. Returns boolean otherwise.
- */
- containsPoint: function(point) {
- var approx = OpenLayers.Number.limitSigDigs;
- var digs = 14;
- var px = approx(point.x, digs);
- var py = approx(point.y, digs);
- function getX(y, x1, y1, x2, y2) {
- return (y - y2) * ((x2 - x1) / (y2 - y1)) + x2;
- }
- var numSeg = this.components.length - 1;
- var start, end, x1, y1, x2, y2, cx, cy;
- var crosses = 0;
- for(var i=0; i<numSeg; ++i) {
- start = this.components[i];
- x1 = approx(start.x, digs);
- y1 = approx(start.y, digs);
- end = this.components[i + 1];
- x2 = approx(end.x, digs);
- y2 = approx(end.y, digs);
-
- /**
- * The following conditions enforce five edge-crossing rules:
- * 1. points coincident with edges are considered contained;
- * 2. an upward edge includes its starting endpoint, and
- * excludes its final endpoint;
- * 3. a downward edge excludes its starting endpoint, and
- * includes its final endpoint;
- * 4. horizontal edges are excluded; and
- * 5. the edge-ray intersection point must be strictly right
- * of the point P.
- */
- if(y1 == y2) {
- // horizontal edge
- if(py == y1) {
- // point on horizontal line
- if(x1 <= x2 && (px >= x1 && px <= x2) || // right or vert
- x1 >= x2 && (px <= x1 && px >= x2)) { // left or vert
- // point on edge
- crosses = -1;
- break;
- }
- }
- // ignore other horizontal edges
- continue;
- }
- cx = approx(getX(py, x1, y1, x2, y2), digs);
- if(cx == px) {
- // point on line
- if(y1 < y2 && (py >= y1 && py <= y2) || // upward
- y1 > y2 && (py <= y1 && py >= y2)) { // downward
- // point on edge
- crosses = -1;
- break;
- }
- }
- if(cx <= px) {
- // no crossing to the right
- continue;
- }
- if(x1 != x2 && (cx < Math.min(x1, x2) || cx > Math.max(x1, x2))) {
- // no crossing
- continue;
- }
- if(y1 < y2 && (py >= y1 && py < y2) || // upward
- y1 > y2 && (py < y1 && py >= y2)) { // downward
- ++crosses;
- }
- }
- var contained = (crosses == -1) ?
- // on edge
- 1 :
- // even (out) or odd (in)
- !!(crosses & 1);
-
- return contained;
- },
-
- /**
- * APIMethod: intersects
- * Determine if the input geometry intersects this one.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} Any type of geometry.
- *
- * Returns:
- * {Boolean} The input geometry intersects this one.
- */
- intersects: function(geometry) {
- var intersect = false;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- intersect = this.containsPoint(geometry);
- } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
- intersect = geometry.intersects(this);
- } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
- intersect = OpenLayers.Geometry.LineString.prototype.intersects.apply(
- this, [geometry]
- );
- } else {
- // check for component intersections
- for(var i=0, len=geometry.components.length; i<len; ++ i) {
- intersect = geometry.components[i].intersects(this);
- if(intersect) {
- break;
- }
- }
- }
- return intersect;
- },
-
- /**
- * APIMethod: getVertices
- * Return a list of all points in this geometry.
- *
- * Parameters:
- * nodes - {Boolean} For lines, only return vertices that are
- * endpoints. If false, for lines, only vertices that are not
- * endpoints will be returned. If not provided, all vertices will
- * be returned.
- *
- * Returns:
- * {Array} A list of all vertices in the geometry.
- */
- getVertices: function(nodes) {
- return (nodes === true) ? [] : this.components.slice(0, this.components.length-1);
- },
-
- CLASS_NAME: "OpenLayers.Geometry.LinearRing"
-});
-/* ======================================================================
- OpenLayers/Util/vendorPrefix.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/SingleFile.js
- */
-
-OpenLayers.Util = OpenLayers.Util || {};
-/**
- * Namespace: OpenLayers.Util.vendorPrefix
- * A collection of utility functions to detect vendor prefixed features
- */
-OpenLayers.Util.vendorPrefix = (function() {
- "use strict";
-
- var VENDOR_PREFIXES = ["", "O", "ms", "Moz", "Webkit"],
- divStyle = document.createElement("div").style,
- cssCache = {},
- jsCache = {};
-
-
- /**
- * Function: domToCss
- * Converts a upper camel case DOM style property name to a CSS property
- * i.e. transformOrigin -> transform-origin
- * or WebkitTransformOrigin -> -webkit-transform-origin
- *
- * Parameters:
- * prefixedDom - {String} The property to convert
- *
- * Returns:
- * {String} The CSS property
- */
- function domToCss(prefixedDom) {
- if (!prefixedDom) { return null; }
- return prefixedDom.
- replace(/([A-Z])/g, function(c) { return "-" + c.toLowerCase(); }).
- replace(/^ms-/, "-ms-");
- }
-
- /**
- * APIMethod: css
- * Detect which property is used for a CSS property
- *
- * Parameters:
- * property - {String} The standard (unprefixed) CSS property name
- *
- * Returns:
- * {String} The standard CSS property, prefixed property or null if not
- * supported
- */
- function css(property) {
- if (cssCache[property] === undefined) {
- var domProperty = property.
- replace(/(-[\s\S])/g, function(c) { return c.charAt(1).toUpperCase(); });
- var prefixedDom = style(domProperty);
- cssCache[property] = domToCss(prefixedDom);
- }
- return cssCache[property];
- }
-
- /**
- * APIMethod: js
- * Detect which property is used for a JS property/method
- *
- * Parameters:
- * obj - {Object} The object to test on
- * property - {String} The standard (unprefixed) JS property name
- *
- * Returns:
- * {String} The standard JS property, prefixed property or null if not
- * supported
- */
- function js(obj, property) {
- if (jsCache[property] === undefined) {
- var tmpProp,
- i = 0,
- l = VENDOR_PREFIXES.length,
- prefix,
- isStyleObj = (typeof obj.cssText !== "undefined");
-
- jsCache[property] = null;
- for(; i<l; i++) {
- prefix = VENDOR_PREFIXES[i];
- if(prefix) {
- if (!isStyleObj) {
- // js prefix should be lower-case, while style
- // properties have upper case on first character
- prefix = prefix.toLowerCase();
- }
- tmpProp = prefix + property.charAt(0).toUpperCase() + property.slice(1);
- } else {
- tmpProp = property;
- }
-
- if(obj[tmpProp] !== undefined) {
- jsCache[property] = tmpProp;
- break;
- }
- }
- }
- return jsCache[property];
- }
-
- /**
- * APIMethod: style
- * Detect which property is used for a DOM style property
- *
- * Parameters:
- * property - {String} The standard (unprefixed) style property name
- *
- * Returns:
- * {String} The standard style property, prefixed property or null if not
- * supported
- */
- function style(property) {
- return js(divStyle, property);
- }
-
- return {
- css: css,
- js: js,
- style: style,
-
- // used for testing
- cssCache: cssCache,
- jsCache: jsCache
- };
-}());
-/* ======================================================================
- OpenLayers/Animation.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/SingleFile.js
- * @requires OpenLayers/Util/vendorPrefix.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 requestAnimationFrame = OpenLayers.Util.vendorPrefix.js(window, "requestAnimationFrame");
- var isNative = !!(requestAnimationFrame);
-
- /**
- * 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] ||
- 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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,
-
- /**
- * APIProperty: minFrameRate
- * {Number} The minimum framerate for animations in frames per second. After
- * each step, the time spent in the animation is compared to the calculated
- * time at this frame rate. If the animation runs longer than the calculated
- * time, the next step is skipped. Default is 30.
- */
- minFrameRate: null,
-
- /**
- * Property: startTime
- * {Number} The timestamp of the first execution step. Used for skipping
- * frames
- */
- startTime: 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 (callbacks (start, eachStep, done),
- * minFrameRate)
- */
- start: function(begin, finish, duration, options) {
- this.playing = true;
- this.begin = begin;
- this.finish = finish;
- this.duration = duration;
- this.callbacks = options.callbacks;
- this.minFrameRate = options.minFrameRate || 30;
- this.time = 0;
- this.startTime = new Date().getTime();
- 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) {
- // skip frames if frame rate drops below threshold
- if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) {
- 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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 (typeof Proj4js == "object") {
- 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 ((typeof Proj4js == "object") && 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;
- var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;
- xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));
- 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Util/vendorPrefix.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 (actual visibility,
- * not the layer's visibility property) 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. The event
- * object may include a *zoomChanged* property that tells whether the
- * zoom has changed.
- * 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
- * updatesize - triggered after the <updateSize> method was executed
- */
-
- /**
- * 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.
- * Default depends on projection; if this is one of those defined in OpenLayers.Projection.defaults
- * (EPSG:4326 or web mercator), maxExtent will be set to the value defined there;
- * else, defaults to null.
- * 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: tileManager
- * {<OpenLayers.TileManager>|Object} By default, and if the build contains
- * TileManager.js, the map will use the TileManager to queue image requests
- * and to cache tile image elements. To create a map without a TileManager
- * configure the map with tileManager: null. To create a TileManager with
- * non-default options, supply the options instead or alternatively supply
- * an instance of {<OpenLayers.TileManager>}.
- */
-
- /**
- * 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 swallow.
- */
- fallThrough: false,
-
- /**
- * APIProperty: autoUpdateSize
- * {Boolean} Should OpenLayers automatically update the size of the map
- * when the resize event is fired. Default is true.
- */
- autoUpdateSize: true,
-
- /**
- * 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,
-
- /**
- * Property: panTween
- * {<OpenLayers.Tween>} Animated panning tween object, see panTo()
- */
- panTween: 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: zoomTween
- * {<OpenLayers.Tween>} Animated zooming tween object, see zoomTo()
- */
- zoomTween: null,
-
- /**
- * APIProperty: zoomMethod
- * {Function} The Easing function to be used for tweening. Default is
- * OpenLayers.Easing.Quad.easeOut. Setting this to 'null' turns off
- * animated zooming.
- */
- zoomMethod: OpenLayers.Easing.Quad.easeOut,
-
- /**
- * Property: zoomDuration
- * {Integer} The number of steps to be passed to the
- * OpenLayers.Tween.start() method when the map is zoomed.
- * Default is 20.
- */
- zoomDuration: 20,
-
- /**
- * 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: layerContainerOriginPx
- * {Object} Cached object representing the layer container origin (in pixels).
- */
- layerContainerOriginPx: 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}
- );
-
- if (OpenLayers.TileManager && this.tileManager !== null) {
- if (!(this.tileManager instanceof OpenLayers.TileManager)) {
- this.tileManager = new OpenLayers.TileManager(this.tileManager);
- }
- this.tileManager.addMap(this);
- }
-
- // the layerContainerDiv is the one that holds all the layers
- id = this.id + "_OpenLayers_Container";
- this.layerContainerDiv = OpenLayers.Util.createDiv(id);
- this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
- this.layerContainerOriginPx = {x: 0, y: 0};
- this.applyTransform();
-
- this.viewPortDiv.appendChild(this.layerContainerDiv);
-
- this.updateSize();
- if(this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
- }
-
- if (this.autoUpdateSize === true) {
- // 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;
- delete this.zoom;
- 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);
- }
- }
-
- if (this.panMethod) {
- this.panTween = new OpenLayers.Tween(this.panMethod);
- }
- if (this.zoomMethod && this.applyTransform.transform) {
- this.zoomTween = new OpenLayers.Tween(this.zoomMethod);
- }
- },
-
- /**
- * 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;
- }
- // make sure zooming doesn't continue after destruction
- if(this.zoomTween) {
- this.zoomTween.stop();
- this.zoomTween = 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);
- }
-
- 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.viewPortDiv.parentNode) {
- this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
- }
- this.viewPortDiv = null;
-
- if (this.tileManager) {
- this.tileManager.removeMap(this);
- this.tileManager = 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);
- }
-
- }
- }
- this.events.triggerEvent("updatesize");
- },
-
- /**
- * 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.panTween && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) {
- 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) {
- if (this.panTween) {
- this.panTween.stop();
- }
- if (this.zoomTween) {
- this.zoomTween.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.layerContainerOriginPx.x -= dx;
- this.minPx.x -= dx;
- this.maxPx.x -= dx;
- }
- if (dy) {
- this.layerContainerOriginPx.y -= dy;
- this.minPx.y -= dy;
- this.maxPx.y -= dy;
- }
- this.applyTransform();
- 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) {
- if (this.baseLayer && this.baseLayer.wrapDateLine) {
- var resolution, resolutions = this.baseLayer.resolutions,
- maxResolution = this.getMaxExtent().getWidth() / this.size.w;
- if (this.getResolutionForZoom(zoom) > maxResolution) {
- if (this.fractionalZoom) {
- zoom = this.getZoomForResolution(maxResolution);
- } else {
- for (var i=zoom|0, ii=resolutions.length; i<ii; ++i) {
- if (resolutions[i] <= maxResolution) {
- zoom = i;
- break;
- }
- }
- }
- }
- }
- return zoom;
- },
-
- /**
- * APIMethod: getMinZoom
- * Returns the minimum zoom level for the current map view. If the base
- * layer is configured with <wrapDateLine> set to true, this will be the
- * first zoom level that shows no more than one world width in the current
- * map viewport. Components that rely on this value (e.g. zoom sliders)
- * should also listen to the map's "updatesize" event and call this method
- * in the "updatesize" listener.
- *
- * Returns:
- * {Number} Minimum zoom level that shows a map not wider than its
- * <baseLayer>'s maxExtent. This is an Integer value, unless the map is
- * configured with <fractionalZoom> set to true.
- */
- getMinZoom: function() {
- return this.adjustZoom(0);
- },
-
- /**
- * 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);
- }
- }
- 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", {
- zoomChanged: zoomChanged
- });
-
- 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.layerContainerOriginPx.x = 0;
- this.layerContainerOriginPx.y = 0;
- this.applyTransform();
- 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 = this.layerContainerOriginPx.x;
- var oldTop = this.layerContainerOriginPx.y;
- var newLeft = Math.round(originPx.x - newPx.x);
- var newTop = Math.round(originPx.y - newPx.y);
- this.applyTransform(
- (this.layerContainerOriginPx.x = newLeft),
- (this.layerContainerOriginPx.y = newTop));
- 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. Zooming will be animated unless the map
- * is configured with {zoomMethod: null}. To zoom without animation, use
- * <setCenter> without a lonlat argument.
- *
- * Parameters:
- * zoom - {Integer}
- */
- zoomTo: function(zoom, xy) {
- // non-API arguments:
- // xy - {<OpenLayers.Pixel>} optional zoom origin
-
- var map = this;
- if (map.isValidZoomLevel(zoom)) {
- if (map.baseLayer.wrapDateLine) {
- zoom = map.adjustZoom(zoom);
- }
- if (map.zoomTween) {
- var currentRes = map.getResolution(),
- targetRes = map.getResolutionForZoom(zoom),
- start = {scale: 1},
- end = {scale: currentRes / targetRes};
- if (map.zoomTween.playing && map.zoomTween.duration < 3 * map.zoomDuration) {
- // update the end scale, and reuse the running zoomTween
- map.zoomTween.finish = {
- scale: map.zoomTween.finish.scale * end.scale
- };
- } else {
- if (!xy) {
- var size = map.getSize();
- xy = {x: size.w / 2, y: size.h / 2};
- }
- map.zoomTween.start(start, end, map.zoomDuration, {
- minFrameRate: 50, // don't spend much time zooming
- callbacks: {
- eachStep: function(data) {
- var containerOrigin = map.layerContainerOriginPx,
- scale = data.scale,
- dx = ((scale - 1) * (containerOrigin.x - xy.x)) | 0,
- dy = ((scale - 1) * (containerOrigin.y - xy.y)) | 0;
- map.applyTransform(containerOrigin.x + dx, containerOrigin.y + dy, scale);
- },
- done: function(data) {
- map.applyTransform();
- var resolution = map.getResolution() / data.scale,
- zoom = map.getZoomForResolution(resolution, true)
- map.moveTo(map.getZoomTargetCenter(xy, resolution), zoom, true);
- }
- }
- });
- }
- } else {
- var center = xy ?
- map.getZoomTargetCenter(xy, map.getResolutionForZoom(zoom)) :
- null;
- map.setCenter(center, 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;
- },
-
- /**
- * Method: getZoomTargetCenter
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} The zoom origin pixel location on the screen
- * resolution - {Float} The resolution we want to get the center for
- *
- * Returns:
- * {<OpenLayers.LonLat>} The location of the map center after the
- * transformation described by the origin xy and the target resolution.
- */
- getZoomTargetCenter: function (xy, resolution) {
- var lonlat = null,
- size = this.getSize(),
- deltaX = size.w/2 - xy.x,
- deltaY = xy.y - size.h/2,
- zoomPoint = this.getLonLatFromPixel(xy);
- if (zoomPoint) {
- lonlat = new OpenLayers.LonLat(
- zoomPoint.lon + deltaX * resolution,
- zoomPoint.lat + deltaY * resolution
- );
- }
- return lonlat;
- },
-
- //
- // 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 = this.layerContainerOriginPx.x;
- var dY = this.layerContainerOriginPx.y;
- 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 = -this.layerContainerOriginPx.x;
- var dY = -this.layerContainerOriginPx.y;
- 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);
- },
-
- /**
- * Method: applyTransform
- * Applies the given transform to the <layerContainerDiv>. This method has
- * a 2-stage fallback from translate3d/scale3d via translate/scale to plain
- * style.left/style.top, in which case no scaling is supported.
- *
- * Parameters:
- * x - {Number} x parameter for the translation. Defaults to the x value of
- * the map's <layerContainerOriginPx>
- * y - {Number} y parameter for the translation. Defaults to the y value of
- * the map's <layerContainerOriginPx>
- * scale - {Number} scale. Defaults to 1 if not provided.
- */
- applyTransform: function(x, y, scale) {
- scale = scale || 1;
- var origin = this.layerContainerOriginPx,
- needTransform = scale !== 1;
- x = x || origin.x;
- y = y || origin.y;
-
- var style = this.layerContainerDiv.style,
- transform = this.applyTransform.transform,
- template = this.applyTransform.template;
-
- if (transform === undefined) {
- transform = OpenLayers.Util.vendorPrefix.style('transform');
- this.applyTransform.transform = transform;
- if (transform) {
- // Try translate3d, but only if the viewPortDiv has a transform
- // defined in a stylesheet
- var computedStyle = OpenLayers.Element.getStyle(this.viewPortDiv,
- OpenLayers.Util.vendorPrefix.css('transform'));
- if (!computedStyle || computedStyle !== 'none') {
- template = ['translate3d(', ',0) ', 'scale3d(', ',1)'];
- style[transform] = [template[0], '0,0', template[1]].join('');
- }
- // If no transform is defined in the stylesheet or translate3d
- // does not stick, use translate and scale
- if (!template || !~style[transform].indexOf(template[0])) {
- template = ['translate(', ') ', 'scale(', ')'];
- }
- this.applyTransform.template = template;
- }
- }
-
- // If we do 3d transforms, we always want to use them. If we do 2d
- // transforms, we only use them when we need to.
- if (transform !== null && (template[0] === 'translate3d(' || needTransform === true)) {
- // Our 2d transforms are combined with style.left and style.top, so
- // adjust x and y values and set the origin as left and top
- if (needTransform === true && template[0] === 'translate(') {
- x -= origin.x;
- y -= origin.y;
- style.left = origin.x + 'px';
- style.top = origin.y + 'px';
- }
- style[transform] = [
- template[0], x, 'px,', y, 'px', template[1],
- template[2], scale, ',', scale, template[3]
- ].join('');
- } else {
- style.left = x + 'px';
- style.top = y + 'px';
- // We previously might have had needTransform, so remove transform
- if (transform !== null) {
- style[transform] = '';
- }
- }
- },
-
- 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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/BaseTypes/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. When using a Vector
- * layer with a Fixed or BBOX strategy, the event object includes
- * a *filter* property holding the OpenLayers.Filter used when
- * calling read on the protocol.
- * loadend - Triggered when layer loading ends. When using a Vector layer
- * with a Fixed or BBOX strategy, the event object includes a
- * *response* property holding an OpenLayers.Protocol.Response object.
- * visibilitychanged - Triggered when the layer's visibility property is
- * changed, e.g. by turning the layer on or off in the layer switcher.
- * Note that the actual visibility of the layer can also change if it
- * gets out of range (see <calculateInRange>). If you also want to catch
- * these cases, register for the map's 'changelayer' event instead.
- * 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 = {};
-
- options = OpenLayers.Util.extend({}, options);
- // make sure we respect alwaysInRange if set on the prototype
- if (this.alwaysInRange != null) {
- options.alwaysInRange = this.alwaysInRange;
- }
- 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.options.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/HTTPRequest.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer.js
- */
-
-/**
- * Class: OpenLayers.Layer.HTTPRequest
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.HTTPRequest = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * Constant: URL_HASH_FACTOR
- * {Float} Used to hash URL param strings for multi-WMS server selection.
- * Set to the Golden Ratio per Knuth's recommendation.
- */
- URL_HASH_FACTOR: (Math.sqrt(5) - 1) / 2,
-
- /**
- * Property: url
- * {Array(String) or String} This is either an array of url strings or
- * a single url string.
- */
- url: null,
-
- /**
- * Property: params
- * {Object} Hashtable of key/value parameters
- */
- params: null,
-
- /**
- * APIProperty: reproject
- * *Deprecated*. See http://docs.openlayers.org/library/spherical_mercator.html
- * for information on the replacement for this functionality.
- * {Boolean} Whether layer should reproject itself based on base layer
- * locations. This allows reprojection onto commercial layers.
- * Default is false: Most layers can't reproject, but layers
- * which can create non-square geographic pixels can, like WMS.
- *
- */
- reproject: false,
-
- /**
- * Constructor: OpenLayers.Layer.HTTPRequest
- *
- * Parameters:
- * name - {String}
- * url - {Array(String) or String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, [name, options]);
- this.url = url;
- if (!this.params) {
- this.params = OpenLayers.Util.extend({}, params);
- }
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.url = null;
- this.params = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: clone
- *
- * Parameters:
- * obj - {Object}
- *
- * Returns:
- * {<OpenLayers.Layer.HTTPRequest>} An exact clone of this
- * <OpenLayers.Layer.HTTPRequest>
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.HTTPRequest(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * APIMethod: setUrl
- *
- * Parameters:
- * newUrl - {String}
- */
- setUrl: function(newUrl) {
- this.url = newUrl;
- },
-
- /**
- * APIMethod: mergeNewParams
- *
- * Parameters:
- * newParams - {Object}
- *
- * Returns:
- * redrawn: {Boolean} whether the layer was actually redrawn.
- */
- mergeNewParams:function(newParams) {
- this.params = OpenLayers.Util.extend(this.params, newParams);
- var ret = this.redraw();
- if(this.map != null) {
- this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "params"
- });
- }
- return ret;
- },
-
- /**
- * APIMethod: redraw
- * Redraws the layer. Returns true if the layer was redrawn, false if not.
- *
- * Parameters:
- * force - {Boolean} Force redraw by adding random parameter.
- *
- * Returns:
- * {Boolean} The layer was redrawn.
- */
- redraw: function(force) {
- if (force) {
- return this.mergeNewParams({"_olSalt": Math.random()});
- } else {
- return OpenLayers.Layer.prototype.redraw.apply(this, []);
- }
- },
-
- /**
- * Method: selectUrl
- * selectUrl() implements the standard floating-point multiplicative
- * hash function described by Knuth, and hashes the contents of the
- * given param string into a float between 0 and 1. This float is then
- * scaled to the size of the provided urls array, and used to select
- * a URL.
- *
- * Parameters:
- * paramString - {String}
- * urls - {Array(String)}
- *
- * Returns:
- * {String} An entry from the urls array, deterministically selected based
- * on the paramString.
- */
- selectUrl: function(paramString, urls) {
- var product = 1;
- for (var i=0, len=paramString.length; i<len; i++) {
- product *= paramString.charCodeAt(i) * this.URL_HASH_FACTOR;
- product -= Math.floor(product);
- }
- return urls[Math.floor(product * urls.length)];
- },
-
- /**
- * Method: getFullRequestString
- * Combine url with layer's params and these newParams.
- *
- * does checking on the serverPath variable, allowing for cases when it
- * is supplied with trailing ? or &, as well as cases where not.
- *
- * return in formatted string like this:
- * "server?key1=value1&key2=value2&key3=value3"
- *
- * WARNING: The altUrl parameter is deprecated and will be removed in 3.0.
- *
- * Parameters:
- * newParams - {Object}
- * altUrl - {String} Use this as the url instead of the layer's url
- *
- * Returns:
- * {String}
- */
- getFullRequestString:function(newParams, altUrl) {
-
- // if not altUrl passed in, use layer's url
- var url = altUrl || this.url;
-
- // create a new params hashtable with all the layer params and the
- // new params together. then convert to string
- var allParams = OpenLayers.Util.extend({}, this.params);
- allParams = OpenLayers.Util.extend(allParams, newParams);
- var paramsString = OpenLayers.Util.getParameterString(allParams);
-
- // if url is not a string, it should be an array of strings,
- // in which case we will deterministically select one of them in
- // order to evenly distribute requests to different urls.
- //
- if (OpenLayers.Util.isArray(url)) {
- url = this.selectUrl(paramsString, url);
- }
-
- // ignore parameters that are already in the url search string
- var urlParams =
- OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));
- for(var key in allParams) {
- if(key.toUpperCase() in urlParams) {
- delete allParams[key];
- }
- }
- paramsString = OpenLayers.Util.getParameterString(allParams);
-
- return OpenLayers.Util.urlAppend(url, paramsString);
- },
-
- CLASS_NAME: "OpenLayers.Layer.HTTPRequest"
-});
-/* ======================================================================
- OpenLayers/Tile.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Tile
- * This is a class designed to designate a single tile, however
- * it is explicitly designed to do relatively little. Tiles store
- * information about themselves -- such as the URL that they are related
- * to, and their size - but do not add themselves to the layer div
- * automatically, for example. Create a new tile with the
- * <OpenLayers.Tile> constructor, or a subclass.
- *
- * TBD 3.0 - remove reference to url in above paragraph
- *
- */
-OpenLayers.Tile = OpenLayers.Class({
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the tile.
- *
- * Register a listener for a particular event with the following syntax:
- * (code)
- * tile.events.register(type, obj, listener);
- * (end)
- *
- * Supported event types:
- * beforedraw - Triggered before the tile is drawn. Used to defer
- * drawing to an animation queue. To defer drawing, listeners need
- * to return false, which will abort drawing. The queue handler needs
- * to call <draw>(true) to actually draw the tile.
- * loadstart - Triggered when tile loading starts.
- * loadend - Triggered when tile loading ends.
- * loaderror - Triggered before the loadend event (i.e. when the tile is
- * still hidden) if the tile could not be loaded.
- * reload - Triggered when an already loading tile is reloaded.
- * unload - Triggered before a tile is unloaded.
- */
- events: 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.
- *
- * This options can be set in the ``tileOptions`` option from
- * <OpenLayers.Layer.Grid>. For example, to be notified of the
- * ``loadend`` event of each tiles:
- * (code)
- * new OpenLayers.Layer.OSM('osm', 'http://tile.openstreetmap.org/${z}/${x}/${y}.png', {
- * tileOptions: {
- * eventListeners: {
- * 'loadend': function(evt) {
- * // do something on loadend
- * }
- * }
- * }
- * });
- * (end)
- */
- eventListeners: null,
-
- /**
- * Property: id
- * {String} null
- */
- id: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer>} layer the tile is attached to
- */
- layer: null,
-
- /**
- * Property: url
- * {String} url of the request.
- *
- * TBD 3.0
- * Deprecated. The base tile class does not need an url. This should be
- * handled in subclasses. Does not belong here.
- */
- url: null,
-
- /**
- * APIProperty: bounds
- * {<OpenLayers.Bounds>} null
- */
- bounds: null,
-
- /**
- * Property: size
- * {<OpenLayers.Size>} null
- */
- size: null,
-
- /**
- * Property: position
- * {<OpenLayers.Pixel>} Top Left pixel of the tile
- */
- position: null,
-
- /**
- * Property: isLoading
- * {Boolean} Is the tile loading?
- */
- isLoading: false,
-
- /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor.
- * there is no need for the base tile class to have a url.
- */
-
- /**
- * Constructor: OpenLayers.Tile
- * Constructor for a new <OpenLayers.Tile> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>}
- * size - {<OpenLayers.Size>}
- * options - {Object}
- */
- initialize: function(layer, position, bounds, url, size, options) {
- this.layer = layer;
- this.position = position.clone();
- this.setBounds(bounds);
- this.url = url;
- if (size) {
- this.size = size.clone();
- }
-
- //give the tile a unique id based on its BBOX.
- this.id = OpenLayers.Util.createUniqueID("Tile_");
-
- OpenLayers.Util.extend(this, options);
-
- this.events = new OpenLayers.Events(this);
- if (this.eventListeners instanceof Object) {
- this.events.on(this.eventListeners);
- }
- },
-
- /**
- * Method: unload
- * Call immediately before destroying if you are listening to tile
- * events, so that counters are properly handled if tile is still
- * loading at destroy-time. Will only fire an event if the tile is
- * still loading.
- */
- unload: function() {
- if (this.isLoading) {
- this.isLoading = false;
- this.events.triggerEvent("unload");
- }
- },
-
- /**
- * APIMethod: destroy
- * Nullify references to prevent circular references and memory leaks.
- */
- destroy:function() {
- this.layer = null;
- this.bounds = null;
- this.size = null;
- this.position = null;
-
- if (this.eventListeners) {
- this.events.un(this.eventListeners);
- }
- this.events.destroy();
- this.eventListeners = null;
- this.events = null;
- },
-
- /**
- * Method: draw
- * Clear whatever is currently in the tile, then return whether or not
- * it should actually be re-drawn. This is an example implementation
- * that can be overridden by subclasses. The minimum thing to do here
- * is to call <clear> and return the result from <shouldDraw>.
- *
- * Parameters:
- * force - {Boolean} If true, the tile will not be cleared and no beforedraw
- * event will be fired. This is used for drawing tiles asynchronously
- * after drawing has been cancelled by returning false from a beforedraw
- * listener.
- *
- * Returns:
- * {Boolean} Whether or not the tile should actually be drawn. Returns null
- * if a beforedraw listener returned false.
- */
- draw: function(force) {
- if (!force) {
- //clear tile's contents and mark as not drawn
- this.clear();
- }
- var draw = this.shouldDraw();
- if (draw && !force && this.events.triggerEvent("beforedraw") === false) {
- draw = null;
- }
- return draw;
- },
-
- /**
- * Method: shouldDraw
- * Return whether or not the tile should actually be (re-)drawn. The only
- * case where we *wouldn't* want to draw the tile is if the tile is outside
- * its layer's maxExtent
- *
- * Returns:
- * {Boolean} Whether or not the tile should actually be drawn.
- */
- shouldDraw: function() {
- var withinMaxExtent = false,
- maxExtent = this.layer.maxExtent;
- if (maxExtent) {
- var map = this.layer.map;
- var worldBounds = map.baseLayer.wrapDateLine && map.getMaxExtent();
- if (this.bounds.intersectsBounds(maxExtent, {inclusive: false, worldBounds: worldBounds})) {
- withinMaxExtent = true;
- }
- }
-
- return withinMaxExtent || this.layer.displayOutsideMaxExtent;
- },
-
- /**
- * Method: setBounds
- * Sets the bounds on this instance
- *
- * Parameters:
- * bounds {<OpenLayers.Bounds>}
- */
- setBounds: function(bounds) {
- bounds = bounds.clone();
- if (this.layer.map.baseLayer.wrapDateLine) {
- var worldExtent = this.layer.map.getMaxExtent(),
- tolerance = this.layer.map.getResolution();
- bounds = bounds.wrapDateLine(worldExtent, {
- leftTolerance: tolerance,
- rightTolerance: tolerance
- });
- }
- this.bounds = bounds;
- },
-
- /**
- * Method: moveTo
- * Reposition the tile.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- * redraw - {Boolean} Call draw method on tile after moving.
- * Default is true
- */
- moveTo: function (bounds, position, redraw) {
- if (redraw == null) {
- redraw = true;
- }
-
- this.setBounds(bounds);
- this.position = position.clone();
- if (redraw) {
- this.draw();
- }
- },
-
- /**
- * Method: clear
- * Clear the tile of any bounds/position-related data so that it can
- * be reused in a new location.
- */
- clear: function(draw) {
- // to be extended by subclasses
- },
-
- CLASS_NAME: "OpenLayers.Tile"
-});
-/* ======================================================================
- OpenLayers/Tile/Image.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Tile.js
- * @requires OpenLayers/Animation.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Tile.Image
- * Instances of OpenLayers.Tile.Image are used to manage the image tiles
- * used by various layers. Create a new image tile with the
- * <OpenLayers.Tile.Image> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Tile>
- */
-OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the tile.
- *
- * Register a listener for a particular event with the following syntax:
- * (code)
- * tile.events.register(type, obj, listener);
- * (end)
- *
- * Supported event types (in addition to the <OpenLayers.Tile> events):
- * beforeload - Triggered before an image is prepared for loading, when the
- * url for the image is known already. Listeners may call <setImage> on
- * the tile instance. If they do so, that image will be used and no new
- * one will be created.
- */
-
- /**
- * APIProperty: url
- * {String} The URL of the image being requested. No default. Filled in by
- * layer.getURL() function. May be modified by loadstart listeners.
- */
- url: null,
-
- /**
- * Property: imgDiv
- * {HTMLImageElement} The image for this tile.
- */
- imgDiv: null,
-
- /**
- * Property: frame
- * {DOMElement} The image element is appended to the frame. Any gutter on
- * the image will be hidden behind the frame. If no gutter is set,
- * this will be null.
- */
- frame: null,
-
- /**
- * Property: imageReloadAttempts
- * {Integer} Attempts to load the image.
- */
- imageReloadAttempts: null,
-
- /**
- * Property: layerAlphaHack
- * {Boolean} True if the png alpha hack needs to be applied on the layer's div.
- */
- layerAlphaHack: null,
-
- /**
- * Property: asyncRequestId
- * {Integer} ID of an request to see if request is still valid. This is a
- * number which increments by 1 for each asynchronous request.
- */
- asyncRequestId: null,
-
- /**
- * APIProperty: maxGetUrlLength
- * {Number} If set, requests that would result in GET urls with more
- * characters than the number provided will be made using form-encoded
- * HTTP POST. It is good practice to avoid urls that are longer than 2048
- * characters.
- *
- * Caution:
- * Older versions of Gecko based browsers (e.g. Firefox < 3.5) and most
- * Opera versions do not fully support this option. On all browsers,
- * transition effects are not supported if POST requests are used.
- */
- maxGetUrlLength: null,
-
- /**
- * Property: canvasContext
- * {CanvasRenderingContext2D} A canvas context associated with
- * the tile image.
- */
- canvasContext: null,
-
- /**
- * APIProperty: crossOriginKeyword
- * The value of the crossorigin keyword to use when loading images. This is
- * only relevant when using <getCanvasContext> for tiles from remote
- * origins and should be set to either 'anonymous' or 'use-credentials'
- * for servers that send Access-Control-Allow-Origin headers with their
- * tiles.
- */
- crossOriginKeyword: null,
-
- /** TBD 3.0 - reorder the parameters to the init function to remove
- * URL. the getUrl() function on the layer gets called on
- * each draw(), so no need to specify it here.
- */
-
- /**
- * Constructor: OpenLayers.Tile.Image
- * Constructor for a new <OpenLayers.Tile.Image> instance.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>} layer that the tile will go in.
- * position - {<OpenLayers.Pixel>}
- * bounds - {<OpenLayers.Bounds>}
- * url - {<String>} Deprecated. Remove me in 3.0.
- * size - {<OpenLayers.Size>}
- * options - {Object}
- */
- initialize: function(layer, position, bounds, url, size, options) {
- OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
- this.url = url; //deprecated remove me
-
- this.layerAlphaHack = this.layer.alpha && OpenLayers.Util.alphaHack();
-
- if (this.maxGetUrlLength != null || this.layer.gutter || this.layerAlphaHack) {
- // only create frame if it's needed
- this.frame = document.createElement("div");
- this.frame.style.position = "absolute";
- this.frame.style.overflow = "hidden";
- }
- if (this.maxGetUrlLength != null) {
- OpenLayers.Util.extend(this, OpenLayers.Tile.Image.IFrame);
- }
- },
-
- /**
- * APIMethod: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- if (this.imgDiv) {
- this.clear();
- this.imgDiv = null;
- this.frame = null;
- }
- // don't handle async requests any more
- this.asyncRequestId = null;
- OpenLayers.Tile.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: draw
- * Check that a tile should be drawn, and draw it.
- *
- * Returns:
- * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned
- * false.
- */
- draw: function() {
- var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments);
- if (shouldDraw) {
- // The layer's reproject option is deprecated.
- if (this.layer != this.layer.map.baseLayer && this.layer.reproject) {
- // getBoundsFromBaseLayer is defined in deprecated.js.
- this.bounds = this.getBoundsFromBaseLayer(this.position);
- }
- if (this.isLoading) {
- //if we're already loading, send 'reload' instead of 'loadstart'.
- this._loadEvent = "reload";
- } else {
- this.isLoading = true;
- this._loadEvent = "loadstart";
- }
- this.renderTile();
- this.positionTile();
- } else if (shouldDraw === false) {
- this.unload();
- }
- return shouldDraw;
- },
-
- /**
- * Method: renderTile
- * Internal function to actually initialize the image tile,
- * position it correctly, and set its url.
- */
- renderTile: function() {
- if (this.layer.async) {
- // Asynchronous image requests call the asynchronous getURL method
- // on the layer to fetch an image that covers 'this.bounds'.
- var id = this.asyncRequestId = (this.asyncRequestId || 0) + 1;
- this.layer.getURLasync(this.bounds, function(url) {
- if (id == this.asyncRequestId) {
- this.url = url;
- this.initImage();
- }
- }, this);
- } else {
- // synchronous image requests get the url immediately.
- this.url = this.layer.getURL(this.bounds);
- this.initImage();
- }
- },
-
- /**
- * Method: positionTile
- * Using the properties currenty set on the layer, position the tile correctly.
- * This method is used both by the async and non-async versions of the Tile.Image
- * code.
- */
- positionTile: function() {
- var style = this.getTile().style,
- size = this.frame ? this.size :
- this.layer.getImageSize(this.bounds),
- ratio = 1;
- if (this.layer instanceof OpenLayers.Layer.Grid) {
- ratio = this.layer.getServerResolution() / this.layer.map.getResolution();
- }
- style.left = this.position.x + "px";
- style.top = this.position.y + "px";
- style.width = Math.round(ratio * size.w) + "px";
- style.height = Math.round(ratio * size.h) + "px";
- },
-
- /**
- * Method: clear
- * Remove the tile from the DOM, clear it of any image related data so that
- * it can be reused in a new location.
- */
- clear: function() {
- OpenLayers.Tile.prototype.clear.apply(this, arguments);
- var img = this.imgDiv;
- if (img) {
- var tile = this.getTile();
- if (tile.parentNode === this.layer.div) {
- this.layer.div.removeChild(tile);
- }
- this.setImgSrc();
- if (this.layerAlphaHack === true) {
- img.style.filter = "";
- }
- OpenLayers.Element.removeClass(img, "olImageLoadError");
- }
- this.canvasContext = null;
- },
-
- /**
- * Method: getImage
- * Returns or creates and returns the tile image.
- */
- getImage: function() {
- if (!this.imgDiv) {
- this.imgDiv = OpenLayers.Tile.Image.IMAGE.cloneNode(false);
-
- var style = this.imgDiv.style;
- if (this.frame) {
- var left = 0, top = 0;
- if (this.layer.gutter) {
- left = this.layer.gutter / this.layer.tileSize.w * 100;
- top = this.layer.gutter / this.layer.tileSize.h * 100;
- }
- style.left = -left + "%";
- style.top = -top + "%";
- style.width = (2 * left + 100) + "%";
- style.height = (2 * top + 100) + "%";
- }
- style.visibility = "hidden";
- style.opacity = 0;
- if (this.layer.opacity < 1) {
- style.filter = 'alpha(opacity=' +
- (this.layer.opacity * 100) +
- ')';
- }
- style.position = "absolute";
- if (this.layerAlphaHack) {
- // move the image out of sight
- style.paddingTop = style.height;
- style.height = "0";
- style.width = "100%";
- }
- if (this.frame) {
- this.frame.appendChild(this.imgDiv);
- }
- }
-
- return this.imgDiv;
- },
-
- /**
- * APIMethod: setImage
- * Sets the image element for this tile. This method should only be called
- * from beforeload listeners.
- *
- * Parameters
- * img - {HTMLImageElement} The image to use for this tile.
- */
- setImage: function(img) {
- this.imgDiv = img;
- },
-
- /**
- * Method: initImage
- * Creates the content for the frame on the tile.
- */
- initImage: function() {
- if (!this.url && !this.imgDiv) {
- // fast path out - if there is no tile url and no previous image
- this.isLoading = false;
- return;
- }
- this.events.triggerEvent('beforeload');
- this.layer.div.appendChild(this.getTile());
- this.events.triggerEvent(this._loadEvent);
- var img = this.getImage();
- var src = img.getAttribute('src') || '';
- if (this.url && OpenLayers.Util.isEquivalentUrl(src, this.url)) {
- this._loadTimeout = window.setTimeout(
- OpenLayers.Function.bind(this.onImageLoad, this), 0
- );
- } else {
- this.stopLoading();
- if (this.crossOriginKeyword) {
- img.removeAttribute("crossorigin");
- }
- OpenLayers.Event.observe(img, "load",
- OpenLayers.Function.bind(this.onImageLoad, this)
- );
- OpenLayers.Event.observe(img, "error",
- OpenLayers.Function.bind(this.onImageError, this)
- );
- this.imageReloadAttempts = 0;
- this.setImgSrc(this.url);
- }
- },
-
- /**
- * Method: setImgSrc
- * Sets the source for the tile image
- *
- * Parameters:
- * url - {String} or undefined to hide the image
- */
- setImgSrc: function(url) {
- var img = this.imgDiv;
- if (url) {
- img.style.visibility = 'hidden';
- img.style.opacity = 0;
- // don't set crossOrigin if the url is a data URL
- if (this.crossOriginKeyword) {
- if (url.substr(0, 5) !== 'data:') {
- img.setAttribute("crossorigin", this.crossOriginKeyword);
- } else {
- img.removeAttribute("crossorigin");
- }
- }
- img.src = url;
- } else {
- // Remove reference to the image, and leave it to the browser's
- // caching and garbage collection.
- this.stopLoading();
- this.imgDiv = null;
- if (img.parentNode) {
- img.parentNode.removeChild(img);
- }
- }
- },
-
- /**
- * Method: getTile
- * Get the tile's markup.
- *
- * Returns:
- * {DOMElement} The tile's markup
- */
- getTile: function() {
- return this.frame ? this.frame : this.getImage();
- },
-
- /**
- * Method: createBackBuffer
- * Create a backbuffer for this tile. A backbuffer isn't exactly a clone
- * of the tile's markup, because we want to avoid the reloading of the
- * image. So we clone the frame, and steal the image from the tile.
- *
- * Returns:
- * {DOMElement} The markup, or undefined if the tile has no image
- * or if it's currently loading.
- */
- createBackBuffer: function() {
- if (!this.imgDiv || this.isLoading) {
- return;
- }
- var backBuffer;
- if (this.frame) {
- backBuffer = this.frame.cloneNode(false);
- backBuffer.appendChild(this.imgDiv);
- } else {
- backBuffer = this.imgDiv;
- }
- this.imgDiv = null;
- return backBuffer;
- },
-
- /**
- * Method: onImageLoad
- * Handler for the image onload event
- */
- onImageLoad: function() {
- var img = this.imgDiv;
- this.stopLoading();
- img.style.visibility = 'inherit';
- img.style.opacity = this.layer.opacity;
- this.isLoading = false;
- this.canvasContext = null;
- this.events.triggerEvent("loadend");
-
- if (this.layerAlphaHack === true) {
- img.style.filter =
- "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
- img.src + "', sizingMethod='scale')";
- }
- },
-
- /**
- * Method: onImageError
- * Handler for the image onerror event
- */
- onImageError: function() {
- var img = this.imgDiv;
- if (img.src != null) {
- this.imageReloadAttempts++;
- if (this.imageReloadAttempts <= OpenLayers.IMAGE_RELOAD_ATTEMPTS) {
- this.setImgSrc(this.layer.getURL(this.bounds));
- } else {
- OpenLayers.Element.addClass(img, "olImageLoadError");
- this.events.triggerEvent("loaderror");
- this.onImageLoad();
- }
- }
- },
-
- /**
- * Method: stopLoading
- * Stops a loading sequence so <onImageLoad> won't be executed.
- */
- stopLoading: function() {
- OpenLayers.Event.stopObservingElement(this.imgDiv);
- window.clearTimeout(this._loadTimeout);
- delete this._loadTimeout;
- },
-
- /**
- * APIMethod: getCanvasContext
- * Returns a canvas context associated with the tile image (with
- * the image drawn on it).
- * Returns undefined if the browser does not support canvas, if
- * the tile has no image or if it's currently loading.
- *
- * The function returns a canvas context instance but the
- * underlying canvas is still available in the 'canvas' property:
- * (code)
- * var context = tile.getCanvasContext();
- * if (context) {
- * var data = context.canvas.toDataURL('image/jpeg');
- * }
- * (end)
- *
- * Returns:
- * {Boolean}
- */
- getCanvasContext: function() {
- if (OpenLayers.CANVAS_SUPPORTED && this.imgDiv && !this.isLoading) {
- if (!this.canvasContext) {
- var canvas = document.createElement("canvas");
- canvas.width = this.size.w;
- canvas.height = this.size.h;
- this.canvasContext = canvas.getContext("2d");
- this.canvasContext.drawImage(this.imgDiv, 0, 0);
- }
- return this.canvasContext;
- }
- },
-
- CLASS_NAME: "OpenLayers.Tile.Image"
-
-});
-
-/**
- * Constant: OpenLayers.Tile.Image.IMAGE
- * {HTMLImageElement} The image for a tile.
- */
-OpenLayers.Tile.Image.IMAGE = (function() {
- var img = new Image();
- img.className = "olTileImage";
- // avoid image gallery menu in IE6
- img.galleryImg = "no";
- return img;
-}());
-
-/* ======================================================================
- OpenLayers/Layer/Grid.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/HTTPRequest.js
- * @requires OpenLayers/Tile/Image.js
- */
-
-/**
- * Class: OpenLayers.Layer.Grid
- * Base class for layers that use a lattice of tiles. Create a new grid
- * layer with the <OpenLayers.Layer.Grid> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.HTTPRequest>
- */
-OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
-
- /**
- * APIProperty: tileSize
- * {<OpenLayers.Size>}
- */
- tileSize: null,
-
- /**
- * Property: tileOriginCorner
- * {String} If the <tileOrigin> property is not provided, the tile origin
- * will be derived from the layer's <maxExtent>. The corner of the
- * <maxExtent> used is determined by this property. Acceptable values
- * are "tl" (top left), "tr" (top right), "bl" (bottom left), and "br"
- * (bottom right). Default is "bl".
- */
- tileOriginCorner: "bl",
-
- /**
- * APIProperty: tileOrigin
- * {<OpenLayers.LonLat>} Optional origin for aligning the grid of tiles.
- * If provided, requests for tiles at all resolutions will be aligned
- * with this location (no tiles shall overlap this location). If
- * not provided, the grid of tiles will be aligned with the layer's
- * <maxExtent>. Default is ``null``.
- */
- tileOrigin: null,
-
- /** APIProperty: tileOptions
- * {Object} optional configuration options for <OpenLayers.Tile> instances
- * created by this Layer, if supported by the tile class.
- */
- tileOptions: null,
-
- /**
- * APIProperty: tileClass
- * {<OpenLayers.Tile>} The tile class to use for this layer.
- * Defaults is OpenLayers.Tile.Image.
- */
- tileClass: OpenLayers.Tile.Image,
-
- /**
- * Property: grid
- * {Array(Array(<OpenLayers.Tile>))} This is an array of rows, each row is
- * an array of tiles.
- */
- grid: null,
-
- /**
- * APIProperty: singleTile
- * {Boolean} Moves the layer into single-tile mode, meaning that one tile
- * will be loaded. The tile's size will be determined by the 'ratio'
- * property. When the tile is dragged such that it does not cover the
- * entire viewport, it is reloaded.
- */
- singleTile: false,
-
- /** APIProperty: ratio
- * {Float} Used only when in single-tile mode, this specifies the
- * ratio of the size of the single tile to the size of the map.
- * Default value is 1.5.
- */
- ratio: 1.5,
-
- /**
- * APIProperty: buffer
- * {Integer} Used only when in gridded mode, this specifies the number of
- * extra rows and colums of tiles on each side which will
- * surround the minimum grid tiles to cover the map.
- * For very slow loading layers, a larger value may increase
- * performance somewhat when dragging, but will increase bandwidth
- * use significantly.
- */
- buffer: 0,
-
- /**
- * APIProperty: transitionEffect
- * {String} The transition effect to use when the map is zoomed.
- * Two posible values:
- *
- * "resize" - Existing tiles are resized on zoom to provide a visual
- * effect of the zoom having taken place immediately. As the
- * new tiles become available, they are drawn on top of the
- * resized tiles (this is the default setting).
- * "map-resize" - Existing tiles are resized on zoom and placed below the
- * base layer. New tiles for the base layer will cover existing tiles.
- * This setting is recommended when having an overlay duplicated during
- * the transition is undesirable (e.g. street labels or big transparent
- * fills).
- * null - No transition effect.
- *
- * Using "resize" on non-opaque layers can cause undesired visual
- * effects. Set transitionEffect to null in this case.
- */
- transitionEffect: "resize",
-
- /**
- * APIProperty: numLoadingTiles
- * {Integer} How many tiles are still loading?
- */
- numLoadingTiles: 0,
-
- /**
- * Property: serverResolutions
- * {Array(Number}} This property is documented in subclasses as
- * an API property.
- */
- serverResolutions: null,
-
- /**
- * Property: loading
- * {Boolean} Indicates if tiles are being loaded.
- */
- loading: false,
-
- /**
- * Property: backBuffer
- * {DOMElement} The back buffer.
- */
- backBuffer: null,
-
- /**
- * Property: gridResolution
- * {Number} The resolution of the current grid. Used for backbuffer and
- * client zoom. This property is updated every time the grid is
- * initialized.
- */
- gridResolution: null,
-
- /**
- * Property: backBufferResolution
- * {Number} The resolution of the current back buffer. This property is
- * updated each time a back buffer is created.
- */
- backBufferResolution: null,
-
- /**
- * Property: backBufferLonLat
- * {Object} The top-left corner of the current back buffer. Includes lon
- * and lat properties. This object is updated each time a back buffer
- * is created.
- */
- backBufferLonLat: null,
-
- /**
- * Property: backBufferTimerId
- * {Number} The id of the back buffer timer. This timer is used to
- * delay the removal of the back buffer, thereby preventing
- * flash effects caused by tile animation.
- */
- backBufferTimerId: null,
-
- /**
- * APIProperty: removeBackBufferDelay
- * {Number} Delay for removing the backbuffer when all tiles have finished
- * loading. Can be set to 0 when no css opacity transitions for the
- * olTileImage class are used. Default is 0 for <singleTile> layers,
- * 2500 for tiled layers. See <className> for more information on
- * tile animation.
- */
- removeBackBufferDelay: null,
-
- /**
- * APIProperty: className
- * {String} Name of the class added to the layer div. If not set in the
- * options passed to the constructor then className defaults to
- * "olLayerGridSingleTile" for single tile layers (see <singleTile>),
- * and "olLayerGrid" for non single tile layers.
- *
- * Note:
- *
- * The displaying of tiles is not animated by default for single tile
- * layers - OpenLayers' default theme (style.css) includes this:
- * (code)
- * .olLayerGrid .olTileImage {
- * -webkit-transition: opacity 0.2s linear;
- * -moz-transition: opacity 0.2s linear;
- * -o-transition: opacity 0.2s linear;
- * transition: opacity 0.2s linear;
- * }
- * (end)
- * To animate tile displaying for any grid layer the following
- * CSS rule can be used:
- * (code)
- * .olTileImage {
- * -webkit-transition: opacity 0.2s linear;
- * -moz-transition: opacity 0.2s linear;
- * -o-transition: opacity 0.2s linear;
- * transition: opacity 0.2s linear;
- * }
- * (end)
- * In that case, to avoid flash effects, <removeBackBufferDelay>
- * should not be zero.
- */
- className: null,
-
- /**
- * 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 event types:
- * addtile - Triggered when a tile is added to this layer. Listeners receive
- * an object as first argument, which has a tile property that
- * references the tile that has been added.
- * tileloadstart - Triggered when a tile starts loading. Listeners receive
- * an object as first argument, which has a tile property that
- * references the tile that starts loading.
- * tileloaded - Triggered when each new tile is
- * loaded, as a means of progress update to listeners.
- * listeners can access 'numLoadingTiles' if they wish to keep
- * track of the loading progress. Listeners are called with an object
- * with a 'tile' property as first argument, making the loaded tile
- * available to the listener, and an 'aborted' property, which will be
- * true when loading was aborted and no tile data is available.
- * tileerror - Triggered before the tileloaded event (i.e. when the tile is
- * still hidden) if a tile failed to load. Listeners receive an object
- * as first argument, which has a tile property that references the
- * tile that could not be loaded.
- * retile - Triggered when the layer recreates its tile grid.
- */
-
- /**
- * Property: gridLayout
- * {Object} Object containing properties tilelon, tilelat, startcol,
- * startrow
- */
- gridLayout: null,
-
- /**
- * Property: rowSign
- * {Number} 1 for grids starting at the top, -1 for grids starting at the
- * bottom. This is used for several grid index and offset calculations.
- */
- rowSign: null,
-
- /**
- * Property: transitionendEvents
- * {Array} Event names for transitionend
- */
- transitionendEvents: [
- 'transitionend', 'webkitTransitionEnd', 'otransitionend',
- 'oTransitionEnd'
- ],
-
- /**
- * Constructor: OpenLayers.Layer.Grid
- * Create a new grid layer
- *
- * Parameters:
- * name - {String}
- * url - {String}
- * params - {Object}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, params, options) {
- OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,
- arguments);
- this.grid = [];
- this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this);
-
- this.initProperties();
-
- this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1;
- },
-
- /**
- * Method: initProperties
- * Set any properties that depend on the value of singleTile.
- * Currently sets removeBackBufferDelay and className
- */
- initProperties: function() {
- if (this.options.removeBackBufferDelay === undefined) {
- this.removeBackBufferDelay = this.singleTile ? 0 : 2500;
- }
-
- if (this.options.className === undefined) {
- this.className = this.singleTile ? 'olLayerGridSingleTile' :
- 'olLayerGrid';
- }
- },
-
- /**
- * Method: setMap
- *
- * Parameters:
- * map - {<OpenLayers.Map>} The map.
- */
- setMap: function(map) {
- OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this, map);
- OpenLayers.Element.addClass(this.div, this.className);
- },
-
- /**
- * Method: removeMap
- * Called when the layer is removed from the map.
- *
- * Parameters:
- * map - {<OpenLayers.Map>} The map.
- */
- removeMap: function(map) {
- this.removeBackBuffer();
- },
-
- /**
- * APIMethod: destroy
- * Deconstruct the layer and clear the grid.
- */
- destroy: function() {
- this.removeBackBuffer();
- this.clearGrid();
-
- this.grid = null;
- this.tileSize = null;
- OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * APIMethod: mergeNewParams
- * Refetches tiles with new params merged, keeping a backbuffer. Each
- * loading new tile will have a css class of '.olTileReplacing'. If a
- * stylesheet applies a 'display: none' style to that class, any fade-in
- * transition will not apply, and backbuffers for each tile will be removed
- * as soon as the tile is loaded.
- *
- * Parameters:
- * newParams - {Object}
- *
- * Returns:
- * redrawn: {Boolean} whether the layer was actually redrawn.
- */
-
- /**
- * Method: clearGrid
- * Go through and remove all tiles from the grid, calling
- * destroy() on each of them to kill circular references
- */
- clearGrid:function() {
- if (this.grid) {
- for(var iRow=0, len=this.grid.length; iRow<len; iRow++) {
- var row = this.grid[iRow];
- for(var iCol=0, clen=row.length; iCol<clen; iCol++) {
- var tile = row[iCol];
- this.destroyTile(tile);
- }
- }
- this.grid = [];
- this.gridResolution = null;
- this.gridLayout = null;
- }
- },
-
- /**
- * 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) {
- var singleTileChanged = newOptions.singleTile !== undefined &&
- newOptions.singleTile !== this.singleTile;
- OpenLayers.Layer.HTTPRequest.prototype.addOptions.apply(this, arguments);
- if (this.map && singleTileChanged) {
- this.initProperties();
- this.clearGrid();
- this.tileSize = this.options.tileSize;
- this.setTileSize();
- this.moveTo(null, true);
- }
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this layer
- *
- * Parameters:
- * obj - {Object} Is this ever used?
- *
- * Returns:
- * {<OpenLayers.Layer.Grid>} An exact clone of this OpenLayers.Layer.Grid
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.Grid(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
- if (this.tileSize != null) {
- obj.tileSize = this.tileSize.clone();
- }
-
- // we do not want to copy reference to grid, so we make a new array
- obj.grid = [];
- obj.gridResolution = null;
- // same for backbuffer
- obj.backBuffer = null;
- obj.backBufferTimerId = null;
- obj.loading = false;
- obj.numLoadingTiles = 0;
-
- return obj;
- },
-
- /**
- * Method: moveTo
- * This function is called whenever the map is moved. All the moving
- * of actual 'tiles' is done by the map, but moveTo's role is to accept
- * a bounds and make sure the data that that bounds requires is pre-loaded.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo:function(bounds, zoomChanged, dragging) {
-
- OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this, arguments);
-
- bounds = bounds || this.map.getExtent();
-
- if (bounds != null) {
-
- // if grid is empty or zoom has changed, we *must* re-tile
- var forceReTile = !this.grid.length || zoomChanged;
-
- // total bounds of the tiles
- var tilesBounds = this.getTilesBounds();
-
- // the new map resolution
- var resolution = this.map.getResolution();
-
- // the server-supported resolution for the new map resolution
- var serverResolution = this.getServerResolution(resolution);
-
- if (this.singleTile) {
-
- // We want to redraw whenever even the slightest part of the
- // current bounds is not contained by our tile.
- // (thus, we do not specify partial -- its default is false)
-
- if ( forceReTile ||
- (!dragging && !tilesBounds.containsBounds(bounds))) {
-
- // In single tile mode with no transition effect, we insert
- // a non-scaled backbuffer when the layer is moved. But if
- // a zoom occurs right after a move, i.e. before the new
- // image is received, we need to remove the backbuffer, or
- // an ill-positioned image will be visible during the zoom
- // transition.
-
- if(zoomChanged && this.transitionEffect !== 'resize') {
- this.removeBackBuffer();
- }
-
- if(!zoomChanged || this.transitionEffect === 'resize') {
- this.applyBackBuffer(resolution);
- }
-
- this.initSingleTile(bounds);
- }
- } else {
-
- // if the bounds have changed such that they are not even
- // *partially* contained by our tiles (e.g. when user has
- // programmatically panned to the other side of the earth on
- // zoom level 18), then moveGriddedTiles could potentially have
- // to run through thousands of cycles, so we want to reTile
- // instead (thus, partial true).
- forceReTile = forceReTile ||
- !tilesBounds.intersectsBounds(bounds, {
- worldBounds: this.map.baseLayer.wrapDateLine &&
- this.map.getMaxExtent()
- });
-
- if(forceReTile) {
- if(zoomChanged && (this.transitionEffect === 'resize' ||
- this.gridResolution === resolution)) {
- this.applyBackBuffer(resolution);
- }
- this.initGriddedTiles(bounds);
- } else {
- this.moveGriddedTiles();
- }
- }
- }
- },
-
- /**
- * Method: getTileData
- * Given a map location, retrieve a tile and the pixel offset within that
- * tile corresponding to the location. If there is not an existing
- * tile in the grid that covers the given location, null will be
- * returned.
- *
- * Parameters:
- * loc - {<OpenLayers.LonLat>} map location
- *
- * Returns:
- * {Object} Object with the following properties: tile ({<OpenLayers.Tile>}),
- * i ({Number} x-pixel offset from top left), and j ({Integer} y-pixel
- * offset from top left).
- */
- getTileData: function(loc) {
- var data = null,
- x = loc.lon,
- y = loc.lat,
- numRows = this.grid.length;
-
- if (this.map && numRows) {
- var res = this.map.getResolution(),
- tileWidth = this.tileSize.w,
- tileHeight = this.tileSize.h,
- bounds = this.grid[0][0].bounds,
- left = bounds.left,
- top = bounds.top;
-
- if (x < left) {
- // deal with multiple worlds
- if (this.map.baseLayer.wrapDateLine) {
- var worldWidth = this.map.getMaxExtent().getWidth();
- var worldsAway = Math.ceil((left - x) / worldWidth);
- x += worldWidth * worldsAway;
- }
- }
- // tile distance to location (fractional number of tiles);
- var dtx = (x - left) / (res * tileWidth);
- var dty = (top - y) / (res * tileHeight);
- // index of tile in grid
- var col = Math.floor(dtx);
- var row = Math.floor(dty);
- if (row >= 0 && row < numRows) {
- var tile = this.grid[row][col];
- if (tile) {
- data = {
- tile: tile,
- // pixel index within tile
- i: Math.floor((dtx - col) * tileWidth),
- j: Math.floor((dty - row) * tileHeight)
- };
- }
- }
- }
- return data;
- },
-
- /**
- * Method: destroyTile
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
- */
- destroyTile: function(tile) {
- this.removeTileMonitoringHooks(tile);
- tile.destroy();
- },
-
- /**
- * Method: getServerResolution
- * Return the closest server-supported resolution.
- *
- * Parameters:
- * resolution - {Number} The base resolution. If undefined the
- * map resolution is used.
- *
- * Returns:
- * {Number} The closest server resolution value.
- */
- getServerResolution: function(resolution) {
- var distance = Number.POSITIVE_INFINITY;
- resolution = resolution || this.map.getResolution();
- if(this.serverResolutions &&
- OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) {
- var i, newDistance, newResolution, serverResolution;
- for(i=this.serverResolutions.length-1; i>= 0; i--) {
- newResolution = this.serverResolutions[i];
- newDistance = Math.abs(newResolution - resolution);
- if (newDistance > distance) {
- break;
- }
- distance = newDistance;
- serverResolution = newResolution;
- }
- resolution = serverResolution;
- }
- return resolution;
- },
-
- /**
- * Method: getServerZoom
- * Return the zoom value corresponding to the best matching server
- * resolution, taking into account <serverResolutions> and <zoomOffset>.
- *
- * Returns:
- * {Number} The closest server supported zoom. This is not the map zoom
- * level, but an index of the server's resolutions array.
- */
- getServerZoom: function() {
- var resolution = this.getServerResolution();
- return this.serverResolutions ?
- OpenLayers.Util.indexOf(this.serverResolutions, resolution) :
- this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0);
- },
-
- /**
- * Method: applyBackBuffer
- * Create, insert, scale and position a back buffer for the layer.
- *
- * Parameters:
- * resolution - {Number} The resolution to transition to.
- */
- applyBackBuffer: function(resolution) {
- if(this.backBufferTimerId !== null) {
- this.removeBackBuffer();
- }
- var backBuffer = this.backBuffer;
- if(!backBuffer) {
- backBuffer = this.createBackBuffer();
- if(!backBuffer) {
- return;
- }
- if (resolution === this.gridResolution) {
- this.div.insertBefore(backBuffer, this.div.firstChild);
- } else {
- this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div);
- }
- this.backBuffer = backBuffer;
-
- // set some information in the instance for subsequent
- // calls to applyBackBuffer where the same back buffer
- // is reused
- var topLeftTileBounds = this.grid[0][0].bounds;
- this.backBufferLonLat = {
- lon: topLeftTileBounds.left,
- lat: topLeftTileBounds.top
- };
- this.backBufferResolution = this.gridResolution;
- }
-
- var ratio = this.backBufferResolution / resolution;
-
- // scale the tiles inside the back buffer
- var tiles = backBuffer.childNodes, tile;
- for (var i=tiles.length-1; i>=0; --i) {
- tile = tiles[i];
- tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px';
- tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px';
- tile.style.width = Math.round(ratio * tile._w) + 'px';
- tile.style.height = Math.round(ratio * tile._h) + 'px';
- }
-
- // and position it (based on the grid's top-left corner)
- var position = this.getViewPortPxFromLonLat(
- this.backBufferLonLat, resolution);
- var leftOffset = this.map.layerContainerOriginPx.x;
- var topOffset = this.map.layerContainerOriginPx.y;
- backBuffer.style.left = Math.round(position.x - leftOffset) + 'px';
- backBuffer.style.top = Math.round(position.y - topOffset) + 'px';
- },
-
- /**
- * Method: createBackBuffer
- * Create a back buffer.
- *
- * Returns:
- * {DOMElement} The DOM element for the back buffer, undefined if the
- * grid isn't initialized yet.
- */
- createBackBuffer: function() {
- var backBuffer;
- if(this.grid.length > 0) {
- backBuffer = document.createElement('div');
- backBuffer.id = this.div.id + '_bb';
- backBuffer.className = 'olBackBuffer';
- backBuffer.style.position = 'absolute';
- var map = this.map;
- backBuffer.style.zIndex = this.transitionEffect === 'resize' ?
- this.getZIndex() - 1 :
- // 'map-resize':
- map.Z_INDEX_BASE.BaseLayer -
- (map.getNumLayers() - map.getLayerIndex(this));
- for(var i=0, lenI=this.grid.length; i<lenI; i++) {
- for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) {
- var tile = this.grid[i][j],
- markup = this.grid[i][j].createBackBuffer();
- if (markup) {
- markup._i = i;
- markup._j = j;
- markup._w = tile.size.w;
- markup._h = tile.size.h;
- markup.id = tile.id + '_bb';
- backBuffer.appendChild(markup);
- }
- }
- }
- }
- return backBuffer;
- },
-
- /**
- * Method: removeBackBuffer
- * Remove back buffer from DOM.
- */
- removeBackBuffer: function() {
- if (this._transitionElement) {
- for (var i=this.transitionendEvents.length-1; i>=0; --i) {
- OpenLayers.Event.stopObserving(this._transitionElement,
- this.transitionendEvents[i], this._removeBackBuffer);
- }
- delete this._transitionElement;
- }
- if(this.backBuffer) {
- if (this.backBuffer.parentNode) {
- this.backBuffer.parentNode.removeChild(this.backBuffer);
- }
- this.backBuffer = null;
- this.backBufferResolution = null;
- if(this.backBufferTimerId !== null) {
- window.clearTimeout(this.backBufferTimerId);
- this.backBufferTimerId = null;
- }
- }
- },
-
- /**
- * Method: moveByPx
- * Move the layer based on pixel vector.
- *
- * Parameters:
- * dx - {Number}
- * dy - {Number}
- */
- moveByPx: function(dx, dy) {
- if (!this.singleTile) {
- this.moveGriddedTiles();
- }
- },
-
- /**
- * APIMethod: setTileSize
- * Check if we are in singleTile mode and if so, set the size as a ratio
- * of the map size (as specified by the layer's 'ratio' property).
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setTileSize: function(size) {
- if (this.singleTile) {
- size = this.map.getSize();
- size.h = parseInt(size.h * this.ratio, 10);
- size.w = parseInt(size.w * this.ratio, 10);
- }
- OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
- },
-
- /**
- * APIMethod: getTilesBounds
- * Return the bounds of the tile grid.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A Bounds object representing the bounds of all the
- * currently loaded tiles (including those partially or not at all seen
- * onscreen).
- */
- getTilesBounds: function() {
- var bounds = null;
-
- var length = this.grid.length;
- if (length) {
- var bottomLeftTileBounds = this.grid[length - 1][0].bounds,
- width = this.grid[0].length * bottomLeftTileBounds.getWidth(),
- height = this.grid.length * bottomLeftTileBounds.getHeight();
-
- bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left,
- bottomLeftTileBounds.bottom,
- bottomLeftTileBounds.left + width,
- bottomLeftTileBounds.bottom + height);
- }
- return bounds;
- },
-
- /**
- * Method: initSingleTile
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- initSingleTile: function(bounds) {
- this.events.triggerEvent("retile");
-
- //determine new tile bounds
- var center = bounds.getCenterLonLat();
- var tileWidth = bounds.getWidth() * this.ratio;
- var tileHeight = bounds.getHeight() * this.ratio;
-
- var tileBounds =
- new OpenLayers.Bounds(center.lon - (tileWidth/2),
- center.lat - (tileHeight/2),
- center.lon + (tileWidth/2),
- center.lat + (tileHeight/2));
-
- var px = this.map.getLayerPxFromLonLat({
- lon: tileBounds.left,
- lat: tileBounds.top
- });
-
- if (!this.grid.length) {
- this.grid[0] = [];
- }
-
- var tile = this.grid[0][0];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
-
- this.addTileMonitoringHooks(tile);
- tile.draw();
- this.grid[0][0] = tile;
- } else {
- tile.moveTo(tileBounds, px);
- }
-
- //remove all but our single tile
- this.removeExcessTiles(1,1);
-
- // store the resolution of the grid
- this.gridResolution = this.getServerResolution();
- },
-
- /**
- * Method: calculateGridLayout
- * Generate parameters for the grid layout.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bound>|Object} OpenLayers.Bounds or an
- * object with a 'left' and 'top' properties.
- * origin - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
- * object with a 'lon' and 'lat' properties.
- * resolution - {Number}
- *
- * Returns:
- * {Object} Object containing properties tilelon, tilelat, startcol,
- * startrow
- */
- calculateGridLayout: function(bounds, origin, resolution) {
- var tilelon = resolution * this.tileSize.w;
- var tilelat = resolution * this.tileSize.h;
-
- var offsetlon = bounds.left - origin.lon;
- var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
-
- var rowSign = this.rowSign;
-
- var offsetlat = rowSign * (origin.lat - bounds.top + tilelat);
- var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat/tilelat) - this.buffer * rowSign;
-
- return {
- tilelon: tilelon, tilelat: tilelat,
- startcol: tilecol, startrow: tilerow
- };
-
- },
-
- /**
- * Method: getTileOrigin
- * Determine the origin for aligning the grid of tiles. If a <tileOrigin>
- * property is supplied, that will be returned. Otherwise, the origin
- * will be derived from the layer's <maxExtent> property. In this case,
- * the tile origin will be the corner of the <maxExtent> given by the
- * <tileOriginCorner> property.
- *
- * Returns:
- * {<OpenLayers.LonLat>} The tile origin.
- */
- getTileOrigin: function() {
- var origin = this.tileOrigin;
- if (!origin) {
- var extent = this.getMaxExtent();
- var edges = ({
- "tl": ["left", "top"],
- "tr": ["right", "top"],
- "bl": ["left", "bottom"],
- "br": ["right", "bottom"]
- })[this.tileOriginCorner];
- origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]);
- }
- return origin;
- },
-
- /**
- * Method: getTileBoundsForGridIndex
- *
- * Parameters:
- * row - {Number} The row of the grid
- * col - {Number} The column of the grid
- *
- * Returns:
- * {<OpenLayers.Bounds>} The bounds for the tile at (row, col)
- */
- getTileBoundsForGridIndex: function(row, col) {
- var origin = this.getTileOrigin();
- var tileLayout = this.gridLayout;
- var tilelon = tileLayout.tilelon;
- var tilelat = tileLayout.tilelat;
- var startcol = tileLayout.startcol;
- var startrow = tileLayout.startrow;
- var rowSign = this.rowSign;
- return new OpenLayers.Bounds(
- origin.lon + (startcol + col) * tilelon,
- origin.lat - (startrow + row * rowSign) * tilelat * rowSign,
- origin.lon + (startcol + col + 1) * tilelon,
- origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign
- );
- },
-
- /**
- * Method: initGriddedTiles
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- */
- initGriddedTiles:function(bounds) {
- this.events.triggerEvent("retile");
-
- // work out mininum number of rows and columns; this is the number of
- // tiles required to cover the viewport plus at least one for panning
-
- var viewSize = this.map.getSize();
-
- var origin = this.getTileOrigin();
- var resolution = this.map.getResolution(),
- serverResolution = this.getServerResolution(),
- ratio = resolution / serverResolution,
- tileSize = {
- w: this.tileSize.w / ratio,
- h: this.tileSize.h / ratio
- };
-
- var minRows = Math.ceil(viewSize.h/tileSize.h) +
- 2 * this.buffer + 1;
- var minCols = Math.ceil(viewSize.w/tileSize.w) +
- 2 * this.buffer + 1;
-
- var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
- this.gridLayout = tileLayout;
-
- var tilelon = tileLayout.tilelon;
- var tilelat = tileLayout.tilelat;
-
- var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
- var layerContainerDivTop = this.map.layerContainerOriginPx.y;
-
- var tileBounds = this.getTileBoundsForGridIndex(0, 0);
- var startPx = this.map.getViewPortPxFromLonLat(
- new OpenLayers.LonLat(tileBounds.left, tileBounds.top)
- );
- startPx.x = Math.round(startPx.x) - layerContainerDivLeft;
- startPx.y = Math.round(startPx.y) - layerContainerDivTop;
-
- var tileData = [], center = this.map.getCenter();
-
- var rowidx = 0;
- do {
- var row = this.grid[rowidx];
- if (!row) {
- row = [];
- this.grid.push(row);
- }
-
- var colidx = 0;
- do {
- tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx);
- var px = startPx.clone();
- px.x = px.x + colidx * Math.round(tileSize.w);
- px.y = px.y + rowidx * Math.round(tileSize.h);
- var tile = row[colidx];
- if (!tile) {
- tile = this.addTile(tileBounds, px);
- this.addTileMonitoringHooks(tile);
- row.push(tile);
- } else {
- tile.moveTo(tileBounds, px, false);
- }
- var tileCenter = tileBounds.getCenterLonLat();
- tileData.push({
- tile: tile,
- distance: Math.pow(tileCenter.lon - center.lon, 2) +
- Math.pow(tileCenter.lat - center.lat, 2)
- });
-
- colidx += 1;
- } while ((tileBounds.right <= bounds.right + tilelon * this.buffer)
- || colidx < minCols);
-
- rowidx += 1;
- } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer)
- || rowidx < minRows);
-
- //shave off exceess rows and colums
- this.removeExcessTiles(rowidx, colidx);
-
- var resolution = this.getServerResolution();
- // store the resolution of the grid
- this.gridResolution = resolution;
-
- //now actually draw the tiles
- tileData.sort(function(a, b) {
- return a.distance - b.distance;
- });
- for (var i=0, ii=tileData.length; i<ii; ++i) {
- tileData[i].tile.draw();
- }
- },
-
- /**
- * Method: getMaxExtent
- * Get this layer's maximum extent. (Implemented as a getter for
- * potential specific implementations in sub-classes.)
- *
- * Returns:
- * {<OpenLayers.Bounds>}
- */
- getMaxExtent: function() {
- return this.maxExtent;
- },
-
- /**
- * APIMethod: addTile
- * Create a tile, initialize it, and add it to the layer div.
- *
- * Parameters
- * bounds - {<OpenLayers.Bounds>}
- * position - {<OpenLayers.Pixel>}
- *
- * Returns:
- * {<OpenLayers.Tile>} The added OpenLayers.Tile
- */
- addTile: function(bounds, position) {
- var tile = new this.tileClass(
- this, position, bounds, null, this.tileSize, this.tileOptions
- );
- this.events.triggerEvent("addtile", {tile: tile});
- return tile;
- },
-
- /**
- * Method: addTileMonitoringHooks
- * This function takes a tile as input and adds the appropriate hooks to
- * the tile so that the layer can keep track of the loading tiles.
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
- */
- addTileMonitoringHooks: function(tile) {
-
- var replacingCls = 'olTileReplacing';
-
- tile.onLoadStart = function() {
- //if that was first tile then trigger a 'loadstart' on the layer
- if (this.loading === false) {
- this.loading = true;
- this.events.triggerEvent("loadstart");
- }
- this.events.triggerEvent("tileloadstart", {tile: tile});
- this.numLoadingTiles++;
- if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) {
- OpenLayers.Element.addClass(tile.getTile(), replacingCls);
- }
- };
-
- tile.onLoadEnd = function(evt) {
- this.numLoadingTiles--;
- var aborted = evt.type === 'unload';
- this.events.triggerEvent("tileloaded", {
- tile: tile,
- aborted: aborted
- });
- if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) {
- var tileDiv = tile.getTile();
- if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') {
- var bufferTile = document.getElementById(tile.id + '_bb');
- if (bufferTile) {
- bufferTile.parentNode.removeChild(bufferTile);
- }
- }
- OpenLayers.Element.removeClass(tileDiv, replacingCls);
- }
- //if that was the last tile, then trigger a 'loadend' on the layer
- if (this.numLoadingTiles === 0) {
- if (this.backBuffer) {
- if (this.backBuffer.childNodes.length === 0) {
- // no tiles transitioning, remove immediately
- this.removeBackBuffer();
- } else {
- // wait until transition has ended or delay has passed
- this._transitionElement = aborted ?
- this.div.lastChild : tile.imgDiv;
- var transitionendEvents = this.transitionendEvents;
- for (var i=transitionendEvents.length-1; i>=0; --i) {
- OpenLayers.Event.observe(this._transitionElement,
- transitionendEvents[i],
- this._removeBackBuffer);
- }
- // the removal of the back buffer is delayed to prevent
- // flash effects due to the animation of tile displaying
- this.backBufferTimerId = window.setTimeout(
- this._removeBackBuffer, this.removeBackBufferDelay
- );
- }
- }
- this.loading = false;
- this.events.triggerEvent("loadend");
- }
- };
-
- tile.onLoadError = function() {
- this.events.triggerEvent("tileerror", {tile: tile});
- };
-
- tile.events.on({
- "loadstart": tile.onLoadStart,
- "loadend": tile.onLoadEnd,
- "unload": tile.onLoadEnd,
- "loaderror": tile.onLoadError,
- scope: this
- });
- },
-
- /**
- * Method: removeTileMonitoringHooks
- * This function takes a tile as input and removes the tile hooks
- * that were added in addTileMonitoringHooks()
- *
- * Parameters:
- * tile - {<OpenLayers.Tile>}
- */
- removeTileMonitoringHooks: function(tile) {
- tile.unload();
- tile.events.un({
- "loadstart": tile.onLoadStart,
- "loadend": tile.onLoadEnd,
- "unload": tile.onLoadEnd,
- "loaderror": tile.onLoadError,
- scope: this
- });
- },
-
- /**
- * Method: moveGriddedTiles
- */
- moveGriddedTiles: function() {
- var buffer = this.buffer + 1;
- while(true) {
- var tlTile = this.grid[0][0];
- var tlViewPort = {
- x: tlTile.position.x +
- this.map.layerContainerOriginPx.x,
- y: tlTile.position.y +
- this.map.layerContainerOriginPx.y
- };
- var ratio = this.getServerResolution() / this.map.getResolution();
- var tileSize = {
- w: Math.round(this.tileSize.w * ratio),
- h: Math.round(this.tileSize.h * ratio)
- };
- if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
- this.shiftColumn(true, tileSize);
- } else if (tlViewPort.x < -tileSize.w * buffer) {
- this.shiftColumn(false, tileSize);
- } else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
- this.shiftRow(true, tileSize);
- } else if (tlViewPort.y < -tileSize.h * buffer) {
- this.shiftRow(false, tileSize);
- } else {
- break;
- }
- }
- },
-
- /**
- * Method: shiftRow
- * Shifty grid work
- *
- * Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
- * tileSize - {Object} rendered tile size; object with w and h properties
- */
- shiftRow: function(prepend, tileSize) {
- var grid = this.grid;
- var rowIndex = prepend ? 0 : (grid.length - 1);
- var sign = prepend ? -1 : 1;
- var rowSign = this.rowSign;
- var tileLayout = this.gridLayout;
- tileLayout.startrow += sign * rowSign;
-
- var modelRow = grid[rowIndex];
- var row = grid[prepend ? 'pop' : 'shift']();
- for (var i=0, len=row.length; i<len; i++) {
- var tile = row[i];
- var position = modelRow[i].position.clone();
- position.y += tileSize.h * sign;
- tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position);
- }
- grid[prepend ? 'unshift' : 'push'](row);
- },
-
- /**
- * Method: shiftColumn
- * Shift grid work in the other dimension
- *
- * Parameters:
- * prepend - {Boolean} if true, prepend to beginning.
- * if false, then append to end
- * tileSize - {Object} rendered tile size; object with w and h properties
- */
- shiftColumn: function(prepend, tileSize) {
- var grid = this.grid;
- var colIndex = prepend ? 0 : (grid[0].length - 1);
- var sign = prepend ? -1 : 1;
- var tileLayout = this.gridLayout;
- tileLayout.startcol += sign;
-
- for (var i=0, len=grid.length; i<len; i++) {
- var row = grid[i];
- var position = row[colIndex].position.clone();
- var tile = row[prepend ? 'pop' : 'shift']();
- position.x += tileSize.w * sign;
- tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position);
- row[prepend ? 'unshift' : 'push'](tile);
- }
- },
-
- /**
- * Method: removeExcessTiles
- * When the size of the map or the buffer changes, we may need to
- * remove some excess rows and columns.
- *
- * Parameters:
- * rows - {Integer} Maximum number of rows we want our grid to have.
- * columns - {Integer} Maximum number of columns we want our grid to have.
- */
- removeExcessTiles: function(rows, columns) {
- var i, l;
-
- // remove extra rows
- while (this.grid.length > rows) {
- var row = this.grid.pop();
- for (i=0, l=row.length; i<l; i++) {
- var tile = row[i];
- this.destroyTile(tile);
- }
- }
-
- // remove extra columns
- for (i=0, l=this.grid.length; i<l; i++) {
- while (this.grid[i].length > columns) {
- var row = this.grid[i];
- var tile = row.pop();
- this.destroyTile(tile);
- }
- }
- },
-
- /**
- * Method: onMapResize
- * For singleTile layers, this will set a new tile size according to the
- * dimensions of the map pane.
- */
- onMapResize: function() {
- if (this.singleTile) {
- this.clearGrid();
- this.setTileSize();
- }
- },
-
- /**
- * APIMethod: getTileBounds
- * Returns The tile bounds for a layer given a pixel location.
- *
- * Parameters:
- * viewPortPx - {<OpenLayers.Pixel>} The location in the viewport.
- *
- * Returns:
- * {<OpenLayers.Bounds>} Bounds of the tile at the given pixel location.
- */
- getTileBounds: function(viewPortPx) {
- var maxExtent = this.maxExtent;
- var resolution = this.getResolution();
- var tileMapWidth = resolution * this.tileSize.w;
- var tileMapHeight = resolution * this.tileSize.h;
- var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);
- var tileLeft = maxExtent.left + (tileMapWidth *
- Math.floor((mapPoint.lon -
- maxExtent.left) /
- tileMapWidth));
- var tileBottom = maxExtent.bottom + (tileMapHeight *
- Math.floor((mapPoint.lat -
- maxExtent.bottom) /
- tileMapHeight));
- return new OpenLayers.Bounds(tileLeft, tileBottom,
- tileLeft + tileMapWidth,
- tileBottom + tileMapHeight);
- },
-
- CLASS_NAME: "OpenLayers.Layer.Grid"
-});
-/* ======================================================================
- OpenLayers/Layer/XYZ.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- */
-
-/**
- * Class: OpenLayers.Layer.XYZ
- * The XYZ class is designed to make it easier for people who have tiles
- * arranged by a standard XYZ grid.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.XYZ = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * APIProperty: isBaseLayer
- * Default is true, as this is designed to be a base tile source.
- */
- isBaseLayer: true,
-
- /**
- * APIProperty: sphericalMercator
- * Whether the tile extents should be set to the defaults for
- * spherical mercator. Useful for things like OpenStreetMap.
- * Default is false, except for the OSM subclass.
- */
- sphericalMercator: false,
-
- /**
- * APIProperty: zoomOffset
- * {Number} If your cache has more zoom levels than you want to provide
- * access to with this layer, supply a zoomOffset. This zoom offset
- * is added to the current map zoom level to determine the level
- * for a requested tile. For example, if you supply a zoomOffset
- * of 3, when the map is at the zoom 0, tiles will be requested from
- * level 3 of your cache. Default is 0 (assumes cache level and map
- * zoom are equivalent). Using <zoomOffset> is an alternative to
- * setting <serverResolutions> if you only want to expose a subset
- * of the server resolutions.
- */
- zoomOffset: 0,
-
- /**
- * APIProperty: serverResolutions
- * {Array} A list of all resolutions available on the server. Only set this
- * property if the map resolutions differ from the server. This
- * property serves two purposes. (a) <serverResolutions> can include
- * resolutions that the server supports and that you don't want to
- * provide with this layer; you can also look at <zoomOffset>, which is
- * an alternative to <serverResolutions> for that specific purpose.
- * (b) The map can work with resolutions that aren't supported by
- * the server, i.e. that aren't in <serverResolutions>. When the
- * map is displayed in such a resolution data for the closest
- * server-supported resolution is loaded and the layer div is
- * stretched as necessary.
- */
- serverResolutions: null,
-
- /**
- * Constructor: OpenLayers.Layer.XYZ
- *
- * Parameters:
- * name - {String}
- * url - {String}
- * options - {Object} Hashtable of extra options to tag onto the layer
- */
- initialize: function(name, url, options) {
- if (options && options.sphericalMercator || this.sphericalMercator) {
- options = OpenLayers.Util.extend({
- projection: "EPSG:900913",
- numZoomLevels: 19
- }, options);
- }
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, [
- name || this.name, url || this.url, {}, options
- ]);
- },
-
- /**
- * APIMethod: clone
- * Create a clone of this layer
- *
- * Parameters:
- * obj - {Object} Is this ever used?
- *
- * Returns:
- * {<OpenLayers.Layer.XYZ>} An exact clone of this OpenLayers.Layer.XYZ
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.XYZ(this.name,
- this.url,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- return obj;
- },
-
- /**
- * Method: getURL
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters
- */
- getURL: function (bounds) {
- var xyz = this.getXYZ(bounds);
- var url = this.url;
- if (OpenLayers.Util.isArray(url)) {
- var s = '' + xyz.x + xyz.y + xyz.z;
- url = this.selectUrl(s, url);
- }
-
- return OpenLayers.String.format(url, xyz);
- },
-
- /**
- * Method: getXYZ
- * Calculates x, y and z for the given bounds.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- *
- * Returns:
- * {Object} - an object with x, y and z properties.
- */
- getXYZ: function(bounds) {
- var res = this.getServerResolution();
- var x = Math.round((bounds.left - this.maxExtent.left) /
- (res * this.tileSize.w));
- var y = Math.round((this.maxExtent.top - bounds.top) /
- (res * this.tileSize.h));
- var z = this.getServerZoom();
-
- if (this.wrapDateLine) {
- var limit = Math.pow(2, z);
- x = ((x % limit) + limit) % limit;
- }
-
- return {'x': x, 'y': y, 'z': z};
- },
-
- /* APIMethod: setMap
- * When the layer is added to a map, then we can fetch our origin
- * (if we don't have one.)
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
- if (!this.tileOrigin) {
- this.tileOrigin = new OpenLayers.LonLat(this.maxExtent.left,
- this.maxExtent.bottom);
- }
- },
-
- CLASS_NAME: "OpenLayers.Layer.XYZ"
-});
-/* ======================================================================
- OpenLayers/Layer/OSM.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/XYZ.js
- */
-
-/**
- * Class: OpenLayers.Layer.OSM
- * This layer allows accessing OpenStreetMap tiles. By default the OpenStreetMap
- * hosted tile.openstreetmap.org Mapnik tileset is used. If you wish to use
- * a different layer instead, you need to provide a different
- * URL to the constructor. Here's an example for using OpenCycleMap:
- *
- * (code)
- * new OpenLayers.Layer.OSM("OpenCycleMap",
- * ["http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
- * "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
- * "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"]);
- * (end)
- *
- * Inherits from:
- * - <OpenLayers.Layer.XYZ>
- */
-OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
-
- /**
- * APIProperty: name
- * {String} The layer name. Defaults to "OpenStreetMap" if the first
- * argument to the constructor is null or undefined.
- */
- name: "OpenStreetMap",
-
- /**
- * APIProperty: url
- * {String} The tileset URL scheme. Defaults to
- * : http://[a|b|c].tile.openstreetmap.org/${z}/${x}/${y}.png
- * (the official OSM tileset) if the second argument to the constructor
- * is null or undefined. To use another tileset you can have something
- * like this:
- * (code)
- * new OpenLayers.Layer.OSM("OpenCycleMap",
- * ["http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
- * "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
- * "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"]);
- * (end)
- */
- url: [
- 'http://a.tile.openstreetmap.org/${z}/${x}/${y}.png',
- 'http://b.tile.openstreetmap.org/${z}/${x}/${y}.png',
- 'http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'
- ],
-
- /**
- * Property: attribution
- * {String} The layer attribution.
- */
- attribution: "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",
-
- /**
- * Property: sphericalMercator
- * {Boolean}
- */
- sphericalMercator: true,
-
- /**
- * Property: wrapDateLine
- * {Boolean}
- */
- wrapDateLine: true,
-
- /** APIProperty: tileOptions
- * {Object} optional configuration options for <OpenLayers.Tile> instances
- * created by this Layer. Default is
- *
- * (code)
- * {crossOriginKeyword: 'anonymous'}
- * (end)
- *
- * When using OSM tilesets other than the default ones, it may be
- * necessary to set this to
- *
- * (code)
- * {crossOriginKeyword: null}
- * (end)
- *
- * if the server does not send Access-Control-Allow-Origin headers.
- */
- tileOptions: null,
-
- /**
- * Constructor: OpenLayers.Layer.OSM
- *
- * Parameters:
- * name - {String} The layer name.
- * url - {String} The tileset URL scheme.
- * options - {Object} Configuration options for the layer. Any inherited
- * layer option can be set in this object (e.g.
- * <OpenLayers.Layer.Grid.buffer>).
- */
- initialize: function(name, url, options) {
- OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
- this.tileOptions = OpenLayers.Util.extend({
- crossOriginKeyword: 'anonymous'
- }, this.options && this.options.tileOptions);
- },
-
- /**
- * Method: clone
- */
- clone: function(obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.OSM(
- this.name, this.url, this.getOptions());
- }
- obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
- return obj;
- },
-
- CLASS_NAME: "OpenLayers.Layer.OSM"
-});
-/* ======================================================================
- OpenLayers/Renderer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- */
-
-/**
- * Class: OpenLayers.Renderer
- * This is the base class for all renderers.
- *
- * This is based on a merger code written by Paul Spencer and Bertil Chapuis.
- * It is largely composed of virtual functions that are to be implemented
- * in technology-specific subclasses, but there is some generic code too.
- *
- * The functions that *are* implemented here merely deal with the maintenance
- * of the size and extent variables, as well as the cached 'resolution'
- * value.
- *
- * A note to the user that all subclasses should use getResolution() instead
- * of directly accessing this.resolution in order to correctly use the
- * cacheing system.
- *
- */
-OpenLayers.Renderer = OpenLayers.Class({
-
- /**
- * Property: container
- * {DOMElement}
- */
- container: null,
-
- /**
- * Property: root
- * {DOMElement}
- */
- root: null,
-
- /**
- * Property: extent
- * {<OpenLayers.Bounds>}
- */
- extent: null,
-
- /**
- * Property: locked
- * {Boolean} If the renderer is currently in a state where many things
- * are changing, the 'locked' property is set to true. This means
- * that renderers can expect at least one more drawFeature event to be
- * called with the 'locked' property set to 'true': In some renderers,
- * this might make sense to use as a 'only update local information'
- * flag.
- */
- locked: false,
-
- /**
- * Property: size
- * {<OpenLayers.Size>}
- */
- size: null,
-
- /**
- * Property: resolution
- * {Float} cache of current map resolution
- */
- resolution: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>} Reference to the map -- this is set in Vector's setMap()
- */
- map: null,
-
- /**
- * Property: featureDx
- * {Number} Feature offset in x direction. Will be calculated for and
- * applied to the current feature while rendering (see
- * <calculateFeatureDx>).
- */
- featureDx: 0,
-
- /**
- * Constructor: OpenLayers.Renderer
- *
- * Parameters:
- * containerID - {<String>}
- * options - {Object} options for this renderer. See sublcasses for
- * supported options.
- */
- initialize: function(containerID, options) {
- this.container = OpenLayers.Util.getElement(containerID);
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- this.container = null;
- this.extent = null;
- this.size = null;
- this.resolution = null;
- this.map = null;
- },
-
- /**
- * APIMethod: supported
- * This should be overridden by specific subclasses
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the renderer class
- */
- supported: function() {
- return false;
- },
-
- /**
- * Method: setExtent
- * Set the visible part of the layer.
- *
- * Resolution has probably changed, so we nullify the resolution
- * cache (this.resolution) -- this way it will be re-computed when
- * next it is needed.
- * We nullify the resolution cache (this.resolution) if resolutionChanged
- * is set to true - this way it will be re-computed on the next
- * getResolution() request.
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- *
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- * False otherwise.
- */
- setExtent: function(extent, resolutionChanged) {
- this.extent = extent.clone();
- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
- var ratio = extent.getWidth() / this.map.getExtent().getWidth(),
- extent = extent.scale(1 / ratio);
- this.extent = extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);
- }
- if (resolutionChanged) {
- this.resolution = null;
- }
- return true;
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Resolution has probably changed, so we nullify the resolution
- * cache (this.resolution) -- this way it will be re-computed when
- * next it is needed.
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setSize: function(size) {
- this.size = size.clone();
- this.resolution = null;
- },
-
- /**
- * Method: getResolution
- * Uses cached copy of resolution if available to minimize computing
- *
- * Returns:
- * {Float} The current map's resolution
- */
- getResolution: function() {
- this.resolution = this.resolution || this.map.getResolution();
- return this.resolution;
- },
-
- /**
- * Method: drawFeature
- * Draw the feature. The optional style argument can be used
- * to override the feature's own style. This method should only
- * be called from layer.drawFeature().
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {<Object>}
- *
- * Returns:
- * {Boolean} true if the feature has been drawn completely, false if not,
- * undefined if the feature had no geometry
- */
- drawFeature: function(feature, style) {
- if(style == null) {
- style = feature.style;
- }
- if (feature.geometry) {
- var bounds = feature.geometry.getBounds();
- if(bounds) {
- var worldBounds;
- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
- worldBounds = this.map.getMaxExtent();
- }
- if (!bounds.intersectsBounds(this.extent, {worldBounds: worldBounds})) {
- style = {display: "none"};
- } else {
- this.calculateFeatureDx(bounds, worldBounds);
- }
- var rendered = this.drawGeometry(feature.geometry, style, feature.id);
- if(style.display != "none" && style.label && rendered !== false) {
-
- var location = feature.geometry.getCentroid();
- if(style.labelXOffset || style.labelYOffset) {
- var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
- var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
- var res = this.getResolution();
- location.move(xOffset*res, yOffset*res);
- }
- this.drawText(feature.id, style, location);
- } else {
- this.removeText(feature.id);
- }
- return rendered;
- }
- }
- },
-
- /**
- * Method: calculateFeatureDx
- * {Number} Calculates the feature offset in x direction. Looking at the
- * center of the feature bounds and the renderer extent, we calculate how
- * many world widths the two are away from each other. This distance is
- * used to shift the feature as close as possible to the center of the
- * current enderer extent, which ensures that the feature is visible in the
- * current viewport.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} Bounds of the feature
- * worldBounds - {<OpenLayers.Bounds>} Bounds of the world
- */
- calculateFeatureDx: function(bounds, worldBounds) {
- this.featureDx = 0;
- if (worldBounds) {
- var worldWidth = worldBounds.getWidth(),
- rendererCenterX = (this.extent.left + this.extent.right) / 2,
- featureCenterX = (bounds.left + bounds.right) / 2,
- worldsAway = Math.round((featureCenterX - rendererCenterX) / worldWidth);
- this.featureDx = worldsAway * worldWidth;
- }
- },
-
- /**
- * Method: drawGeometry
- *
- * Draw a geometry. This should only be called from the renderer itself.
- * Use layer.drawFeature() from outside the renderer.
- * virtual function
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {<String>}
- */
- drawGeometry: function(geometry, style, featureId) {},
-
- /**
- * Method: drawText
- * Function for drawing text labels.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- * style -
- * location - {<OpenLayers.Geometry.Point>}
- */
- drawText: function(featureId, style, location) {},
-
- /**
- * Method: removeText
- * Function for removing text labels.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- */
- removeText: function(featureId) {},
-
- /**
- * Method: clear
- * Clear all vectors from the renderer.
- * virtual function.
- */
- clear: function() {},
-
- /**
- * Method: getFeatureIdFromEvent
- * Returns a feature id from an event on the renderer.
- * How this happens is specific to the renderer. This should be
- * called from layer.getFeatureFromEvent().
- * Virtual function.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {String} A feature id or undefined.
- */
- getFeatureIdFromEvent: function(evt) {},
-
- /**
- * Method: eraseFeatures
- * This is called by the layer to erase features
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- if(!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- for(var i=0, len=features.length; i<len; ++i) {
- var feature = features[i];
- this.eraseGeometry(feature.geometry, feature.id);
- this.removeText(feature.id);
- }
- },
-
- /**
- * Method: eraseGeometry
- * Remove a geometry from the renderer (by id).
- * virtual function.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {},
-
- /**
- * Method: moveRoot
- * moves this renderer's root to a (different) renderer.
- * To be implemented by subclasses that require a common renderer root for
- * feature selection.
- *
- * Parameters:
- * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
- */
- moveRoot: function(renderer) {},
-
- /**
- * Method: getRenderLayerId
- * Gets the layer that this renderer's output appears on. If moveRoot was
- * used, this will be different from the id of the layer containing the
- * features rendered by this renderer.
- *
- * Returns:
- * {String} the id of the output layer.
- */
- getRenderLayerId: function() {
- return this.container.id;
- },
-
- /**
- * Method: applyDefaultSymbolizer
- *
- * Parameters:
- * symbolizer - {Object}
- *
- * Returns:
- * {Object}
- */
- applyDefaultSymbolizer: function(symbolizer) {
- var result = OpenLayers.Util.extend({},
- OpenLayers.Renderer.defaultSymbolizer);
- if(symbolizer.stroke === false) {
- delete result.strokeWidth;
- delete result.strokeColor;
- }
- if(symbolizer.fill === false) {
- delete result.fillColor;
- }
- OpenLayers.Util.extend(result, symbolizer);
- return result;
- },
-
- CLASS_NAME: "OpenLayers.Renderer"
-});
-
-/**
- * Constant: OpenLayers.Renderer.defaultSymbolizer
- * {Object} Properties from this symbolizer will be applied to symbolizers
- * with missing properties. This can also be used to set a global
- * symbolizer default in OpenLayers. To be SLD 1.x compliant, add the
- * following code before rendering any vector features:
- * (code)
- * OpenLayers.Renderer.defaultSymbolizer = {
- * fillColor: "#808080",
- * fillOpacity: 1,
- * strokeColor: "#000000",
- * strokeOpacity: 1,
- * strokeWidth: 1,
- * pointRadius: 3,
- * graphicName: "square"
- * };
- * (end)
- */
-OpenLayers.Renderer.defaultSymbolizer = {
- fillColor: "#000000",
- strokeColor: "#000000",
- strokeWidth: 2,
- fillOpacity: 1,
- strokeOpacity: 1,
- pointRadius: 0,
- labelAlign: 'cm'
-};
-
-
-
-/**
- * Constant: OpenLayers.Renderer.symbol
- * Coordinate arrays for well known (named) symbols.
- */
-OpenLayers.Renderer.symbol = {
- "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
- 303,215, 231,161, 321,161, 350,75],
- "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
- 4,0],
- "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
- "square": [0,0, 0,1, 1,1, 1,0, 0,0],
- "triangle": [0,10, 10,10, 5,0, 0,10]
-};
-/* ======================================================================
- OpenLayers/Renderer/Canvas.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Renderer.js
- */
-
-/**
- * Class: OpenLayers.Renderer.Canvas
- * A renderer based on the 2D 'canvas' drawing element.
- *
- * Inherits:
- * - <OpenLayers.Renderer>
- */
-OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
-
- /**
- * APIProperty: hitDetection
- * {Boolean} Allow for hit detection of features. Default is true.
- */
- hitDetection: true,
-
- /**
- * Property: hitOverflow
- * {Number} The method for converting feature identifiers to color values
- * supports 16777215 sequential values. Two features cannot be
- * predictably detected if their identifiers differ by more than this
- * value. The hitOverflow allows for bigger numbers (but the
- * difference in values is still limited).
- */
- hitOverflow: 0,
-
- /**
- * Property: canvas
- * {Canvas} The canvas context object.
- */
- canvas: null,
-
- /**
- * Property: features
- * {Object} Internal object of feature/style pairs for use in redrawing the layer.
- */
- features: null,
-
- /**
- * Property: pendingRedraw
- * {Boolean} The renderer needs a redraw call to render features added while
- * the renderer was locked.
- */
- pendingRedraw: false,
-
- /**
- * Property: cachedSymbolBounds
- * {Object} Internal cache of calculated symbol extents.
- */
- cachedSymbolBounds: {},
-
- /**
- * Constructor: OpenLayers.Renderer.Canvas
- *
- * Parameters:
- * containerID - {<String>}
- * options - {Object} Optional properties to be set on the renderer.
- */
- initialize: function(containerID, options) {
- OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
- this.root = document.createElement("canvas");
- this.container.appendChild(this.root);
- this.canvas = this.root.getContext("2d");
- this.features = {};
- if (this.hitDetection) {
- this.hitCanvas = document.createElement("canvas");
- this.hitContext = this.hitCanvas.getContext("2d");
- }
- },
-
- /**
- * Method: setExtent
- * Set the visible part of the layer.
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- *
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- * False otherwise.
- */
- setExtent: function() {
- OpenLayers.Renderer.prototype.setExtent.apply(this, arguments);
- // always redraw features
- return false;
- },
-
- /**
- * Method: eraseGeometry
- * Erase a geometry from the renderer. Because the Canvas renderer has
- * 'memory' of the features that it has drawn, we have to remove the
- * feature so it doesn't redraw.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {
- this.eraseFeatures(this.features[featureId][0]);
- },
-
- /**
- * APIMethod: supported
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the renderer class
- */
- supported: function() {
- return OpenLayers.CANVAS_SUPPORTED;
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Once the size is updated, redraw the canvas.
- *
- * Parameters:
- * size - {<OpenLayers.Size>}
- */
- setSize: function(size) {
- this.size = size.clone();
- var root = this.root;
- root.style.width = size.w + "px";
- root.style.height = size.h + "px";
- root.width = size.w;
- root.height = size.h;
- this.resolution = null;
- if (this.hitDetection) {
- var hitCanvas = this.hitCanvas;
- hitCanvas.style.width = size.w + "px";
- hitCanvas.style.height = size.h + "px";
- hitCanvas.width = size.w;
- hitCanvas.height = size.h;
- }
- },
-
- /**
- * Method: drawFeature
- * Draw the feature. Stores the feature in the features list,
- * then redraws the layer.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {<Object>}
- *
- * Returns:
- * {Boolean} The feature has been drawn completely. If the feature has no
- * geometry, undefined will be returned. If the feature is not rendered
- * for other reasons, false will be returned.
- */
- drawFeature: function(feature, style) {
- var rendered;
- if (feature.geometry) {
- style = this.applyDefaultSymbolizer(style || feature.style);
- // don't render if display none or feature outside extent
- var bounds = feature.geometry.getBounds();
-
- var worldBounds;
- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
- worldBounds = this.map.getMaxExtent();
- }
-
- var intersects = bounds && bounds.intersectsBounds(this.extent, {worldBounds: worldBounds});
-
- rendered = (style.display !== "none") && !!bounds && intersects;
- if (rendered) {
- // keep track of what we have rendered for redraw
- this.features[feature.id] = [feature, style];
- }
- else {
- // remove from features tracked for redraw
- delete(this.features[feature.id]);
- }
- this.pendingRedraw = true;
- }
- if (this.pendingRedraw && !this.locked) {
- this.redraw();
- this.pendingRedraw = false;
- }
- return rendered;
- },
-
- /**
- * Method: drawGeometry
- * Used when looping (in redraw) over the features; draws
- * the canvas.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- */
- drawGeometry: function(geometry, style, featureId) {
- var className = geometry.CLASS_NAME;
- if ((className == "OpenLayers.Geometry.Collection") ||
- (className == "OpenLayers.Geometry.MultiPoint") ||
- (className == "OpenLayers.Geometry.MultiLineString") ||
- (className == "OpenLayers.Geometry.MultiPolygon")) {
- for (var i = 0; i < geometry.components.length; i++) {
- this.drawGeometry(geometry.components[i], style, featureId);
- }
- return;
- }
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- this.drawPoint(geometry, style, featureId);
- break;
- case "OpenLayers.Geometry.LineString":
- this.drawLineString(geometry, style, featureId);
- break;
- case "OpenLayers.Geometry.LinearRing":
- this.drawLinearRing(geometry, style, featureId);
- break;
- case "OpenLayers.Geometry.Polygon":
- this.drawPolygon(geometry, style, featureId);
- break;
- default:
- break;
- }
- },
-
- /**
- * Method: drawExternalGraphic
- * Called to draw External graphics.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawExternalGraphic: function(geometry, style, featureId) {
- var img = new Image();
-
- var title = style.title || style.graphicTitle;
- if (title) {
- img.title = title;
- }
-
- var width = style.graphicWidth || style.graphicHeight;
- var height = style.graphicHeight || style.graphicWidth;
- width = width ? width : style.pointRadius * 2;
- height = height ? height : style.pointRadius * 2;
- var xOffset = (style.graphicXOffset != undefined) ?
- style.graphicXOffset : -(0.5 * width);
- var yOffset = (style.graphicYOffset != undefined) ?
- style.graphicYOffset : -(0.5 * height);
-
- var opacity = style.graphicOpacity || style.fillOpacity;
-
- var onLoad = function() {
- if(!this.features[featureId]) {
- return;
- }
- var pt = this.getLocalXY(geometry);
- var p0 = pt[0];
- var p1 = pt[1];
- if(!isNaN(p0) && !isNaN(p1)) {
- var x = (p0 + xOffset) | 0;
- var y = (p1 + yOffset) | 0;
- var canvas = this.canvas;
- canvas.globalAlpha = opacity;
- var factor = OpenLayers.Renderer.Canvas.drawImageScaleFactor ||
- (OpenLayers.Renderer.Canvas.drawImageScaleFactor =
- /android 2.1/.test(navigator.userAgent.toLowerCase()) ?
- // 320 is the screen width of the G1 phone, for
- // which drawImage works out of the box.
- 320 / window.screen.width : 1
- );
- canvas.drawImage(
- img, x*factor, y*factor, width*factor, height*factor
- );
- if (this.hitDetection) {
- this.setHitContextStyle("fill", featureId);
- this.hitContext.fillRect(x, y, width, height);
- }
- }
- };
-
- img.onload = OpenLayers.Function.bind(onLoad, this);
- img.src = style.externalGraphic;
- },
-
- /**
- * Method: drawNamedSymbol
- * Called to draw Well Known Graphic Symbol Name.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawNamedSymbol: function(geometry, style, featureId) {
- var x, y, cx, cy, i, symbolBounds, scaling, angle;
- var unscaledStrokeWidth;
- var deg2rad = Math.PI / 180.0;
-
- var symbol = OpenLayers.Renderer.symbol[style.graphicName];
-
- if (!symbol) {
- throw new Error(style.graphicName + ' is not a valid symbol name');
- }
-
- if (!symbol.length || symbol.length < 2) return;
-
- var pt = this.getLocalXY(geometry);
- var p0 = pt[0];
- var p1 = pt[1];
-
- if (isNaN(p0) || isNaN(p1)) return;
-
- // Use rounded line caps
- this.canvas.lineCap = "round";
- this.canvas.lineJoin = "round";
-
- if (this.hitDetection) {
- this.hitContext.lineCap = "round";
- this.hitContext.lineJoin = "round";
- }
-
- // Scale and rotate symbols, using precalculated bounds whenever possible.
- if (style.graphicName in this.cachedSymbolBounds) {
- symbolBounds = this.cachedSymbolBounds[style.graphicName];
- } else {
- symbolBounds = new OpenLayers.Bounds();
- for(i = 0; i < symbol.length; i+=2) {
- symbolBounds.extend(new OpenLayers.LonLat(symbol[i], symbol[i+1]));
- }
- this.cachedSymbolBounds[style.graphicName] = symbolBounds;
- }
-
- // Push symbol scaling, translation and rotation onto the transformation stack in reverse order.
- // Don't forget to apply all canvas transformations to the hitContext canvas as well(!)
- this.canvas.save();
- if (this.hitDetection) { this.hitContext.save(); }
-
- // Step 3: place symbol at the desired location
- this.canvas.translate(p0,p1);
- if (this.hitDetection) { this.hitContext.translate(p0,p1); }
-
- // Step 2a. rotate the symbol if necessary
- angle = deg2rad * style.rotation; // will be NaN when style.rotation is undefined.
- if (!isNaN(angle)) {
- this.canvas.rotate(angle);
- if (this.hitDetection) { this.hitContext.rotate(angle); }
- }
-
- // // Step 2: scale symbol such that pointRadius equals half the maximum symbol dimension.
- scaling = 2.0 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight());
- this.canvas.scale(scaling,scaling);
- if (this.hitDetection) { this.hitContext.scale(scaling,scaling); }
-
- // Step 1: center the symbol at the origin
- cx = symbolBounds.getCenterLonLat().lon;
- cy = symbolBounds.getCenterLonLat().lat;
- this.canvas.translate(-cx,-cy);
- if (this.hitDetection) { this.hitContext.translate(-cx,-cy); }
-
- // Don't forget to scale stroke widths, because they are affected by canvas scale transformations as well(!)
- // Alternative: scale symbol coordinates manually, so stroke width scaling is not needed anymore.
- unscaledStrokeWidth = style.strokeWidth;
- style.strokeWidth = unscaledStrokeWidth / scaling;
-
- if (style.fill !== false) {
- this.setCanvasStyle("fill", style);
- this.canvas.beginPath();
- for (i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- if (i == 0) this.canvas.moveTo(x,y);
- this.canvas.lineTo(x,y);
- }
- this.canvas.closePath();
- this.canvas.fill();
-
- if (this.hitDetection) {
- this.setHitContextStyle("fill", featureId, style);
- this.hitContext.beginPath();
- for (i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- if (i == 0) this.canvas.moveTo(x,y);
- this.hitContext.lineTo(x,y);
- }
- this.hitContext.closePath();
- this.hitContext.fill();
- }
- }
-
- if (style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.canvas.beginPath();
- for (i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- if (i == 0) this.canvas.moveTo(x,y);
- this.canvas.lineTo(x,y);
- }
- this.canvas.closePath();
- this.canvas.stroke();
-
-
- if (this.hitDetection) {
- this.setHitContextStyle("stroke", featureId, style, scaling);
- this.hitContext.beginPath();
- for (i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- if (i == 0) this.hitContext.moveTo(x,y);
- this.hitContext.lineTo(x,y);
- }
- this.hitContext.closePath();
- this.hitContext.stroke();
- }
-
- }
-
- style.strokeWidth = unscaledStrokeWidth;
- this.canvas.restore();
- if (this.hitDetection) { this.hitContext.restore(); }
- this.setCanvasStyle("reset");
- },
-
- /**
- * Method: setCanvasStyle
- * Prepare the canvas for drawing by setting various global settings.
- *
- * Parameters:
- * type - {String} one of 'stroke', 'fill', or 'reset'
- * style - {Object} Symbolizer hash
- */
- setCanvasStyle: function(type, style) {
- if (type === "fill") {
- this.canvas.globalAlpha = style['fillOpacity'];
- this.canvas.fillStyle = style['fillColor'];
- } else if (type === "stroke") {
- this.canvas.globalAlpha = style['strokeOpacity'];
- this.canvas.strokeStyle = style['strokeColor'];
- this.canvas.lineWidth = style['strokeWidth'];
- } else {
- this.canvas.globalAlpha = 0;
- this.canvas.lineWidth = 1;
- }
- },
-
- /**
- * Method: featureIdToHex
- * Convert a feature ID string into an RGB hex string.
- *
- * Parameters:
- * featureId - {String} Feature id
- *
- * Returns:
- * {String} RGB hex string.
- */
- featureIdToHex: function(featureId) {
- var id = Number(featureId.split("_").pop()) + 1; // zero for no feature
- if (id >= 16777216) {
- this.hitOverflow = id - 16777215;
- id = id % 16777216 + 1;
- }
- var hex = "000000" + id.toString(16);
- var len = hex.length;
- hex = "#" + hex.substring(len-6, len);
- return hex;
- },
-
- /**
- * Method: setHitContextStyle
- * Prepare the hit canvas for drawing by setting various global settings.
- *
- * Parameters:
- * type - {String} one of 'stroke', 'fill', or 'reset'
- * featureId - {String} The feature id.
- * symbolizer - {<OpenLayers.Symbolizer>} The symbolizer.
- */
- setHitContextStyle: function(type, featureId, symbolizer, strokeScaling) {
- var hex = this.featureIdToHex(featureId);
- if (type == "fill") {
- this.hitContext.globalAlpha = 1.0;
- this.hitContext.fillStyle = hex;
- } else if (type == "stroke") {
- this.hitContext.globalAlpha = 1.0;
- this.hitContext.strokeStyle = hex;
- // bump up stroke width to deal with antialiasing. If strokeScaling is defined, we're rendering a symbol
- // on a transformed canvas, so the antialias width bump has to scale as well.
- if (typeof strokeScaling === "undefined") {
- this.hitContext.lineWidth = symbolizer.strokeWidth + 2;
- } else {
- if (!isNaN(strokeScaling)) { this.hitContext.lineWidth = symbolizer.strokeWidth + 2.0 / strokeScaling; }
- }
- } else {
- this.hitContext.globalAlpha = 0;
- this.hitContext.lineWidth = 1;
- }
- },
-
- /**
- * Method: drawPoint
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawPoint: function(geometry, style, featureId) {
- if(style.graphic !== false) {
- if(style.externalGraphic) {
- this.drawExternalGraphic(geometry, style, featureId);
- } else if (style.graphicName && (style.graphicName != "circle")) {
- this.drawNamedSymbol(geometry, style, featureId);
- } else {
- var pt = this.getLocalXY(geometry);
- var p0 = pt[0];
- var p1 = pt[1];
- if(!isNaN(p0) && !isNaN(p1)) {
- var twoPi = Math.PI*2;
- var radius = style.pointRadius;
- if(style.fill !== false) {
- this.setCanvasStyle("fill", style);
- this.canvas.beginPath();
- this.canvas.arc(p0, p1, radius, 0, twoPi, true);
- this.canvas.fill();
- if (this.hitDetection) {
- this.setHitContextStyle("fill", featureId, style);
- this.hitContext.beginPath();
- this.hitContext.arc(p0, p1, radius, 0, twoPi, true);
- this.hitContext.fill();
- }
- }
-
- if(style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.canvas.beginPath();
- this.canvas.arc(p0, p1, radius, 0, twoPi, true);
- this.canvas.stroke();
- if (this.hitDetection) {
- this.setHitContextStyle("stroke", featureId, style);
- this.hitContext.beginPath();
- this.hitContext.arc(p0, p1, radius, 0, twoPi, true);
- this.hitContext.stroke();
- }
- this.setCanvasStyle("reset");
- }
- }
- }
- }
- },
-
- /**
- * Method: drawLineString
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawLineString: function(geometry, style, featureId) {
- style = OpenLayers.Util.applyDefaults({fill: false}, style);
- this.drawLinearRing(geometry, style, featureId);
- },
-
- /**
- * Method: drawLinearRing
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawLinearRing: function(geometry, style, featureId) {
- if (style.fill !== false) {
- this.setCanvasStyle("fill", style);
- this.renderPath(this.canvas, geometry, style, featureId, "fill");
- if (this.hitDetection) {
- this.setHitContextStyle("fill", featureId, style);
- this.renderPath(this.hitContext, geometry, style, featureId, "fill");
- }
- }
- if (style.stroke !== false) {
- this.setCanvasStyle("stroke", style);
- this.renderPath(this.canvas, geometry, style, featureId, "stroke");
- if (this.hitDetection) {
- this.setHitContextStyle("stroke", featureId, style);
- this.renderPath(this.hitContext, geometry, style, featureId, "stroke");
- }
- }
- this.setCanvasStyle("reset");
- },
-
- /**
- * Method: renderPath
- * Render a path with stroke and optional fill.
- */
- renderPath: function(context, geometry, style, featureId, type) {
- var components = geometry.components;
- var len = components.length;
- context.beginPath();
- var start = this.getLocalXY(components[0]);
- var x = start[0];
- var y = start[1];
- if (!isNaN(x) && !isNaN(y)) {
- context.moveTo(start[0], start[1]);
- for (var i=1; i<len; ++i) {
- var pt = this.getLocalXY(components[i]);
- context.lineTo(pt[0], pt[1]);
- }
- if (type === "fill") {
- context.fill();
- } else {
- context.stroke();
- }
- }
- },
-
- /**
- * Method: drawPolygon
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- */
- drawPolygon: function(geometry, style, featureId) {
- var components = geometry.components;
- var len = components.length;
- this.drawLinearRing(components[0], style, featureId);
- // erase inner rings
- for (var i=1; i<len; ++i) {
- /**
- * Note that this is overly agressive. Here we punch holes through
- * all previously rendered features on the same canvas. A better
- * solution for polygons with interior rings would be to draw the
- * polygon on a sketch canvas first. We could erase all holes
- * there and then copy the drawing to the layer canvas.
- * TODO: http://trac.osgeo.org/openlayers/ticket/3130
- */
- this.canvas.globalCompositeOperation = "destination-out";
- if (this.hitDetection) {
- this.hitContext.globalCompositeOperation = "destination-out";
- }
- this.drawLinearRing(
- components[i],
- OpenLayers.Util.applyDefaults({stroke: false, fillOpacity: 1.0}, style),
- featureId
- );
- this.canvas.globalCompositeOperation = "source-over";
- if (this.hitDetection) {
- this.hitContext.globalCompositeOperation = "source-over";
- }
- this.drawLinearRing(
- components[i],
- OpenLayers.Util.applyDefaults({fill: false}, style),
- featureId
- );
- }
- },
-
- /**
- * Method: drawText
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * location - {<OpenLayers.Point>}
- * style - {Object}
- */
- drawText: function(location, style) {
- var pt = this.getLocalXY(location);
-
- this.setCanvasStyle("reset");
- this.canvas.fillStyle = style.fontColor;
- this.canvas.globalAlpha = style.fontOpacity || 1.0;
- var fontStyle = [style.fontStyle ? style.fontStyle : "normal",
- "normal", // "font-variant" not supported
- style.fontWeight ? style.fontWeight : "normal",
- style.fontSize ? style.fontSize : "1em",
- style.fontFamily ? style.fontFamily : "sans-serif"].join(" ");
- var labelRows = style.label.split('\n');
- var numRows = labelRows.length;
- if (this.canvas.fillText) {
- // HTML5
- this.canvas.font = fontStyle;
- this.canvas.textAlign =
- OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
- "center";
- this.canvas.textBaseline =
- OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[1]] ||
- "middle";
- var vfactor =
- OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];
- if (vfactor == null) {
- vfactor = -.5;
- }
- var lineHeight =
- this.canvas.measureText('Mg').height ||
- this.canvas.measureText('xx').width;
- pt[1] += lineHeight*vfactor*(numRows-1);
- for (var i = 0; i < numRows; i++) {
- if (style.labelOutlineWidth) {
- this.canvas.save();
- this.canvas.globalAlpha = style.labelOutlineOpacity || style.fontOpacity || 1.0;
- this.canvas.strokeStyle = style.labelOutlineColor;
- this.canvas.lineWidth = style.labelOutlineWidth;
- this.canvas.strokeText(labelRows[i], pt[0], pt[1] + (lineHeight*i) + 1);
- this.canvas.restore();
- }
- this.canvas.fillText(labelRows[i], pt[0], pt[1] + (lineHeight*i));
- }
- } else if (this.canvas.mozDrawText) {
- // Mozilla pre-Gecko1.9.1 (<FF3.1)
- this.canvas.mozTextStyle = fontStyle;
- // No built-in text alignment, so we measure and adjust the position
- var hfactor =
- OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[0]];
- if (hfactor == null) {
- hfactor = -.5;
- }
- var vfactor =
- OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];
- if (vfactor == null) {
- vfactor = -.5;
- }
- var lineHeight = this.canvas.mozMeasureText('xx');
- pt[1] += lineHeight*(1 + (vfactor*numRows));
- for (var i = 0; i < numRows; i++) {
- var x = pt[0] + (hfactor*this.canvas.mozMeasureText(labelRows[i]));
- var y = pt[1] + (i*lineHeight);
- this.canvas.translate(x, y);
- this.canvas.mozDrawText(labelRows[i]);
- this.canvas.translate(-x, -y);
- }
- }
- this.setCanvasStyle("reset");
- },
-
- /**
- * Method: getLocalXY
- * transform geographic xy into pixel xy
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- */
- getLocalXY: function(point) {
- var resolution = this.getResolution();
- var extent = this.extent;
- var x = ((point.x - this.featureDx) / resolution + (-extent.left / resolution));
- var y = ((extent.top / resolution) - point.y / resolution);
- return [x, y];
- },
-
- /**
- * Method: clear
- * Clear all vectors from the renderer.
- */
- clear: function() {
- var height = this.root.height;
- var width = this.root.width;
- this.canvas.clearRect(0, 0, width, height);
- this.features = {};
- if (this.hitDetection) {
- this.hitContext.clearRect(0, 0, width, height);
- }
- },
-
- /**
- * Method: getFeatureIdFromEvent
- * Returns a feature id from an event on the renderer.
- *
- * Parameters:
- * evt - {<OpenLayers.Event>}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector} A feature or undefined. This method returns a
- * feature instead of a feature id to avoid an unnecessary lookup on the
- * layer.
- */
- getFeatureIdFromEvent: function(evt) {
- var featureId, feature;
-
- if (this.hitDetection && this.root.style.display !== "none") {
- // this dragging check should go in the feature handler
- if (!this.map.dragging) {
- var xy = evt.xy;
- var x = xy.x | 0;
- var y = xy.y | 0;
- var data = this.hitContext.getImageData(x, y, 1, 1).data;
- if (data[3] === 255) { // antialiased
- var id = data[2] + (256 * (data[1] + (256 * data[0])));
- if (id) {
- featureId = "OpenLayers_Feature_Vector_" + (id - 1 + this.hitOverflow);
- try {
- feature = this.features[featureId][0];
- } catch(err) {
- // Because of antialiasing on the canvas, when the hit location is at a point where the edge of
- // one symbol intersects the interior of another symbol, a wrong hit color (and therefore id) results.
- // todo: set Antialiasing = 'off' on the hitContext as soon as browsers allow it.
- }
- }
- }
- }
- }
- return feature;
- },
-
- /**
- * Method: eraseFeatures
- * This is called by the layer to erase features; removes the feature from
- * the list, then redraws the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- if(!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- for(var i=0; i<features.length; ++i) {
- delete this.features[features[i].id];
- }
- this.redraw();
- },
-
- /**
- * Method: redraw
- * The real 'meat' of the function: any time things have changed,
- * redraw() can be called to loop over all the data and (you guessed
- * it) redraw it. Unlike Elements-based Renderers, we can't interact
- * with things once they're drawn, to remove them, for example, so
- * instead we have to just clear everything and draw from scratch.
- */
- redraw: function() {
- if (!this.locked) {
- var height = this.root.height;
- var width = this.root.width;
- this.canvas.clearRect(0, 0, width, height);
- if (this.hitDetection) {
- this.hitContext.clearRect(0, 0, width, height);
- }
- var labelMap = [];
- var feature, geometry, style;
- var worldBounds = (this.map.baseLayer && this.map.baseLayer.wrapDateLine) && this.map.getMaxExtent();
- for (var id in this.features) {
- if (!this.features.hasOwnProperty(id)) { continue; }
- feature = this.features[id][0];
- geometry = feature.geometry;
- this.calculateFeatureDx(geometry.getBounds(), worldBounds);
- style = this.features[id][1];
- this.drawGeometry(geometry, style, feature.id);
- if(style.label) {
- labelMap.push([feature, style]);
- }
- }
- var item;
- for (var i=0, len=labelMap.length; i<len; ++i) {
- item = labelMap[i];
- this.drawText(item[0].geometry.getCentroid(), item[1]);
- }
- }
- },
-
- CLASS_NAME: "OpenLayers.Renderer.Canvas"
-});
-
-/**
- * Constant: OpenLayers.Renderer.Canvas.LABEL_ALIGN
- * {Object}
- */
-OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
- "l": "left",
- "r": "right",
- "t": "top",
- "b": "bottom"
-};
-
-/**
- * Constant: OpenLayers.Renderer.Canvas.LABEL_FACTOR
- * {Object}
- */
-OpenLayers.Renderer.Canvas.LABEL_FACTOR = {
- "l": 0,
- "r": -1,
- "t": 0,
- "b": -1
-};
-
-/**
- * Constant: OpenLayers.Renderer.Canvas.drawImageScaleFactor
- * {Number} Scale factor to apply to the canvas drawImage arguments. This
- * is always 1 except for Android 2.1 devices, to work around
- * http://code.google.com/p/android/issues/detail?id=5141.
- */
-OpenLayers.Renderer.Canvas.drawImageScaleFactor = null;
-/* ======================================================================
- OpenLayers/Handler.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Events.js
- */
-
-/**
- * Class: OpenLayers.Handler
- * Base class to construct a higher-level handler for event sequences. All
- * handlers have activate and deactivate methods. In addition, they have
- * methods named like browser events. When a handler is activated, any
- * additional methods named like a browser event is registered as a
- * listener for the corresponding event. When a handler is deactivated,
- * those same methods are unregistered as event listeners.
- *
- * Handlers also typically have a callbacks object with keys named like
- * the abstracted events or event sequences that they are in charge of
- * handling. The controls that wrap handlers define the methods that
- * correspond to these abstract events - so instead of listening for
- * individual browser events, they only listen for the abstract events
- * defined by the handler.
- *
- * Handlers are created by controls, which ultimately have the responsibility
- * of making changes to the the state of the application. Handlers
- * themselves may make temporary changes, but in general are expected to
- * return the application in the same state that they found it.
- */
-OpenLayers.Handler = OpenLayers.Class({
-
- /**
- * Property: id
- * {String}
- */
- id: null,
-
- /**
- * APIProperty: control
- * {<OpenLayers.Control>}. The control that initialized this handler. The
- * control is assumed to have a valid map property - that map is used
- * in the handler's own setMap method.
- */
- control: null,
-
- /**
- * Property: map
- * {<OpenLayers.Map>}
- */
- map: null,
-
- /**
- * APIProperty: keyMask
- * {Integer} Use bitwise operators and one or more of the OpenLayers.Handler
- * constants to construct a keyMask. The keyMask is used by
- * <checkModifiers>. If the keyMask matches the combination of keys
- * down on an event, checkModifiers returns true.
- *
- * Example:
- * (code)
- * // handler only responds if the Shift key is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT;
- *
- * // handler only responds if Ctrl-Shift is down
- * handler.keyMask = OpenLayers.Handler.MOD_SHIFT |
- * OpenLayers.Handler.MOD_CTRL;
- * (end)
- */
- keyMask: null,
-
- /**
- * Property: active
- * {Boolean}
- */
- active: false,
-
- /**
- * Property: evt
- * {Event} This property references the last event handled by the handler.
- * Note that this property is not part of the stable API. Use of the
- * evt property should be restricted to controls in the library
- * or other applications that are willing to update with changes to
- * the OpenLayers code.
- */
- evt: null,
-
- /**
- * Property: touch
- * {Boolean} Indicates the support of touch events. When touch events are
- * started touch will be true and all mouse related listeners will do
- * nothing.
- */
- touch: false,
-
- /**
- * Constructor: OpenLayers.Handler
- * Construct a handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that initialized this
- * handler. The control is assumed to have a valid map property; that
- * map is used in the handler's own setMap method. If a map property
- * is present in the options argument it will be used instead.
- * callbacks - {Object} An object whose properties correspond to abstracted
- * events or sequences of browser events. The values for these
- * properties are functions defined by the control that get called by
- * the handler.
- * options - {Object} An optional object whose properties will be set on
- * the handler.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Util.extend(this, options);
- this.control = control;
- this.callbacks = callbacks;
-
- var map = this.map || control.map;
- if (map) {
- this.setMap(map);
- }
-
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * Method: setMap
- */
- setMap: function (map) {
- this.map = map;
- },
-
- /**
- * Method: checkModifiers
- * Check the keyMask on the handler. If no <keyMask> is set, this always
- * returns true. If a <keyMask> is set and it matches the combination
- * of keys down on an event, this returns true.
- *
- * Returns:
- * {Boolean} The keyMask matches the keys down on an event.
- */
- checkModifiers: function (evt) {
- if(this.keyMask == null) {
- return true;
- }
- /* calculate the keyboard modifier mask for this event */
- var keyModifiers =
- (evt.shiftKey ? OpenLayers.Handler.MOD_SHIFT : 0) |
- (evt.ctrlKey ? OpenLayers.Handler.MOD_CTRL : 0) |
- (evt.altKey ? OpenLayers.Handler.MOD_ALT : 0) |
- (evt.metaKey ? OpenLayers.Handler.MOD_META : 0);
-
- /* if it differs from the handler object's key mask,
- bail out of the event handler */
- return (keyModifiers == this.keyMask);
- },
-
- /**
- * APIMethod: activate
- * Turn on the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean} The handler was activated.
- */
- activate: function() {
- if(this.active) {
- return false;
- }
- // register for event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i=0, len=events.length; i<len; i++) {
- if (this[events[i]]) {
- this.register(events[i], this[events[i]]);
- }
- }
- this.active = true;
- return true;
- },
-
- /**
- * APIMethod: deactivate
- * Turn off the handler. Returns false if the handler was already inactive.
- *
- * Returns:
- * {Boolean} The handler was deactivated.
- */
- deactivate: function() {
- if(!this.active) {
- return false;
- }
- // unregister event handlers defined on this class.
- var events = OpenLayers.Events.prototype.BROWSER_EVENTS;
- for (var i=0, len=events.length; i<len; i++) {
- if (this[events[i]]) {
- this.unregister(events[i], this[events[i]]);
- }
- }
- this.touch = false;
- this.active = false;
- return true;
- },
-
- /**
- * Method: startTouch
- * Start touch events, this method must be called by subclasses in
- * "touchstart" method. When touch events are started <touch> will be
- * true and all mouse related listeners will do nothing.
- */
- startTouch: function() {
- if (!this.touch) {
- this.touch = true;
- var events = [
- "mousedown", "mouseup", "mousemove", "click", "dblclick",
- "mouseout"
- ];
- for (var i=0, len=events.length; i<len; i++) {
- if (this[events[i]]) {
- this.unregister(events[i], this[events[i]]);
- }
- }
- }
- },
-
- /**
- * Method: callback
- * Trigger the control's named callback with the given arguments
- *
- * Parameters:
- * name - {String} The key for the callback that is one of the properties
- * of the handler's callbacks object.
- * args - {Array(*)} An array of arguments (any type) with which to call
- * the callback (defined by the control).
- */
- callback: function (name, args) {
- if (name && this.callbacks[name]) {
- this.callbacks[name].apply(this.control, args);
- }
- },
-
- /**
- * Method: register
- * register an event on the map
- */
- register: function (name, method) {
- // TODO: deal with registerPriority in 3.0
- this.map.events.registerPriority(name, this, method);
- this.map.events.registerPriority(name, this, this.setEvent);
- },
-
- /**
- * Method: unregister
- * unregister an event from the map
- */
- unregister: function (name, method) {
- this.map.events.unregister(name, this, method);
- this.map.events.unregister(name, this, this.setEvent);
- },
-
- /**
- * Method: setEvent
- * With each registered browser event, the handler sets its own evt
- * property. This property can be accessed by controls if needed
- * to get more information about the event that the handler is
- * processing.
- *
- * This allows modifier keys on the event to be checked (alt, shift, ctrl,
- * and meta cannot be checked with the keyboard handler). For a
- * control to determine which modifier keys are associated with the
- * event that a handler is currently processing, it should access
- * (code)handler.evt.altKey || handler.evt.shiftKey ||
- * handler.evt.ctrlKey || handler.evt.metaKey(end).
- *
- * Parameters:
- * evt - {Event} The browser event.
- */
- setEvent: function(evt) {
- this.evt = evt;
- return true;
- },
-
- /**
- * Method: destroy
- * Deconstruct the handler.
- */
- destroy: function () {
- // unregister event listeners
- this.deactivate();
- // eliminate circular references
- this.control = this.map = null;
- },
-
- CLASS_NAME: "OpenLayers.Handler"
-});
-
-/**
- * Constant: OpenLayers.Handler.MOD_NONE
- * If set as the <keyMask>, <checkModifiers> returns false if any key is down.
- */
-OpenLayers.Handler.MOD_NONE = 0;
-
-/**
- * Constant: OpenLayers.Handler.MOD_SHIFT
- * If set as the <keyMask>, <checkModifiers> returns false if Shift is down.
- */
-OpenLayers.Handler.MOD_SHIFT = 1;
-
-/**
- * Constant: OpenLayers.Handler.MOD_CTRL
- * If set as the <keyMask>, <checkModifiers> returns false if Ctrl is down.
- */
-OpenLayers.Handler.MOD_CTRL = 2;
-
-/**
- * Constant: OpenLayers.Handler.MOD_ALT
- * If set as the <keyMask>, <checkModifiers> returns false if Alt is down.
- */
-OpenLayers.Handler.MOD_ALT = 4;
-
-/**
- * Constant: OpenLayers.Handler.MOD_META
- * If set as the <keyMask>, <checkModifiers> returns false if Cmd is down.
- */
-OpenLayers.Handler.MOD_META = 8;
-
-
-/* ======================================================================
- OpenLayers/Handler/Drag.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Drag
- * The drag handler is used to deal with sequences of browser events related
- * to dragging. The handler is used by controls that want to know when
- * a drag sequence begins, when a drag is happening, and when it has
- * finished.
- *
- * Controls that use the drag handler typically construct it with callbacks
- * for 'down', 'move', and 'done'. Callbacks for these keys are called
- * when the drag begins, with each move, and when the drag is done. In
- * addition, controls can have callbacks keyed to 'up' and 'out' if they
- * care to differentiate between the types of events that correspond with
- * the end of a drag sequence. If no drag actually occurs (no mouse move)
- * the 'down' and 'up' callbacks will be called, but not the 'done'
- * callback.
- *
- * Create a new drag handler with the <OpenLayers.Handler.Drag> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Drag = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: started
- * {Boolean} When a mousedown or touchstart event is received, we want to
- * record it, but not set 'dragging' until the mouse moves after starting.
- */
- started: false,
-
- /**
- * Property: stopDown
- * {Boolean} Stop propagation of mousedown events from getting to listeners
- * on the same element. Default is true.
- */
- stopDown: true,
-
- /**
- * Property: dragging
- * {Boolean}
- */
- dragging: false,
-
- /**
- * Property: last
- * {<OpenLayers.Pixel>} The last pixel location of the drag.
- */
- last: null,
-
- /**
- * Property: start
- * {<OpenLayers.Pixel>} The first pixel location of the drag.
- */
- start: null,
-
- /**
- * Property: lastMoveEvt
- * {Object} The last mousemove event that occurred. Used to
- * position the map correctly when our "delay drag"
- * timeout expired.
- */
- lastMoveEvt: null,
-
- /**
- * Property: oldOnselectstart
- * {Function}
- */
- oldOnselectstart: null,
-
- /**
- * Property: interval
- * {Integer} In order to increase performance, an interval (in
- * milliseconds) can be set to reduce the number of drag events
- * called. If set, a new drag event will not be set until the
- * interval has passed.
- * Defaults to 0, meaning no interval.
- */
- interval: 0,
-
- /**
- * Property: timeoutId
- * {String} The id of the timeout used for the mousedown interval.
- * This is "private", and should be left alone.
- */
- timeoutId: null,
-
- /**
- * APIProperty: documentDrag
- * {Boolean} If set to true, the handler will also handle mouse moves when
- * the cursor has moved out of the map viewport. Default is false.
- */
- documentDrag: false,
-
- /**
- * Property: documentEvents
- * {Boolean} Are we currently observing document events?
- */
- documentEvents: null,
-
- /**
- * Constructor: OpenLayers.Handler.Drag
- * Returns OpenLayers.Handler.Drag
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handlers setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished. The callback should
- * expect to recieve a single argument, the pixel location of the event.
- * Callbacks for 'move' and 'done' are supported. You can also speficy
- * callbacks for 'down', 'up', and 'out' to respond to those events.
- * options - {Object}
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
-
- if (this.documentDrag === true) {
- var me = this;
- this._docMove = function(evt) {
- me.mousemove({
- xy: {x: evt.clientX, y: evt.clientY},
- element: document
- });
- };
- this._docUp = function(evt) {
- me.mouseup({xy: {x: evt.clientX, y: evt.clientY}});
- };
- }
- },
-
-
- /**
- * Method: dragstart
- * This private method is factorized from mousedown and touchstart methods
- *
- * Parameters:
- * evt - {Event} The event
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- dragstart: function (evt) {
- var propagate = true;
- this.dragging = false;
- if (this.checkModifiers(evt) &&
- (OpenLayers.Event.isLeftClick(evt) ||
- OpenLayers.Event.isSingleTouch(evt))) {
- this.started = true;
- this.start = evt.xy;
- this.last = evt.xy;
- OpenLayers.Element.addClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.down(evt);
- this.callback("down", [evt.xy]);
-
- // prevent document dragging
- OpenLayers.Event.preventDefault(evt);
-
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = document.onselectstart ?
- document.onselectstart : OpenLayers.Function.True;
- }
- document.onselectstart = OpenLayers.Function.False;
-
- propagate = !this.stopDown;
- } else {
- this.started = false;
- this.start = null;
- this.last = null;
- }
- return propagate;
- },
-
- /**
- * Method: dragmove
- * This private method is factorized from mousemove and touchmove methods
- *
- * Parameters:
- * evt - {Event} The event
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- dragmove: function (evt) {
- this.lastMoveEvt = evt;
- if (this.started && !this.timeoutId && (evt.xy.x != this.last.x ||
- evt.xy.y != this.last.y)) {
- if(this.documentDrag === true && this.documentEvents) {
- if(evt.element === document) {
- this.adjustXY(evt);
- // do setEvent manually because the documentEvents are not
- // registered with the map
- this.setEvent(evt);
- } else {
- this.removeDocumentEvents();
- }
- }
- if (this.interval > 0) {
- this.timeoutId = setTimeout(
- OpenLayers.Function.bind(this.removeTimeout, this),
- this.interval);
- }
- this.dragging = true;
-
- this.move(evt);
- this.callback("move", [evt.xy]);
- if(!this.oldOnselectstart) {
- this.oldOnselectstart = document.onselectstart;
- document.onselectstart = OpenLayers.Function.False;
- }
- this.last = evt.xy;
- }
- return true;
- },
-
- /**
- * Method: dragend
- * This private method is factorized from mouseup and touchend methods
- *
- * Parameters:
- * evt - {Event} The event
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- dragend: function (evt) {
- if (this.started) {
- if(this.documentDrag === true && this.documentEvents) {
- this.adjustXY(evt);
- this.removeDocumentEvents();
- }
- var dragged = (this.start != this.last);
- this.started = false;
- this.dragging = false;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.up(evt);
- this.callback("up", [evt.xy]);
- if(dragged) {
- this.callback("done", [evt.xy]);
- }
- document.onselectstart = this.oldOnselectstart;
- }
- return true;
- },
-
- /**
- * The four methods below (down, move, up, and out) are used by subclasses
- * to do their own processing related to these mouse events.
- */
-
- /**
- * Method: down
- * This method is called during the handling of the mouse down event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse down event
- */
- down: function(evt) {
- },
-
- /**
- * Method: move
- * This method is called during the handling of the mouse move event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse move event
- *
- */
- move: function(evt) {
- },
-
- /**
- * Method: up
- * This method is called during the handling of the mouse up event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse up event
- */
- up: function(evt) {
- },
-
- /**
- * Method: out
- * This method is called during the handling of the mouse out event.
- * Subclasses can do their own processing here.
- *
- * Parameters:
- * evt - {Event} The mouse out event
- */
- out: function(evt) {
- },
-
- /**
- * The methods below are part of the magic of event handling. Because
- * they are named like browser events, they are registered as listeners
- * for the events they represent.
- */
-
- /**
- * Method: mousedown
- * Handle mousedown events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousedown: function(evt) {
- return this.dragstart(evt);
- },
-
- /**
- * Method: touchstart
- * Handle touchstart events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchstart: function(evt) {
- this.startTouch();
- return this.dragstart(evt);
- },
-
- /**
- * Method: mousemove
- * Handle mousemove events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mousemove: function(evt) {
- return this.dragmove(evt);
- },
-
- /**
- * Method: touchmove
- * Handle touchmove events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchmove: function(evt) {
- return this.dragmove(evt);
- },
-
- /**
- * Method: removeTimeout
- * Private. Called by mousemove() to remove the drag timeout.
- */
- removeTimeout: function() {
- this.timeoutId = null;
- // if timeout expires while we're still dragging (mouseup
- // hasn't occurred) then call mousemove to move to the
- // correct position
- if(this.dragging) {
- this.mousemove(this.lastMoveEvt);
- }
- },
-
- /**
- * Method: mouseup
- * Handle mouseup events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseup: function(evt) {
- return this.dragend(evt);
- },
-
- /**
- * Method: touchend
- * Handle touchend events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchend: function(evt) {
- // override evt.xy with last position since touchend does not have
- // any touch position
- evt.xy = this.last;
- return this.dragend(evt);
- },
-
- /**
- * Method: mouseout
- * Handle mouseout events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- mouseout: function (evt) {
- if (this.started && OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {
- if(this.documentDrag === true) {
- this.addDocumentEvents();
- } else {
- var dragged = (this.start != this.last);
- this.started = false;
- this.dragging = false;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- this.out(evt);
- this.callback("out", []);
- if(dragged) {
- this.callback("done", [evt.xy]);
- }
- if(document.onselectstart) {
- document.onselectstart = this.oldOnselectstart;
- }
- }
- }
- return true;
- },
-
- /**
- * Method: click
- * The drag handler captures the click event. If something else registers
- * for clicks on the same element, its listener will not be called
- * after a drag.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- click: function (evt) {
- // let the click event propagate only if the mouse moved
- return (this.start == this.last);
- },
-
- /**
- * Method: activate
- * Activate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully activated.
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.dragging = false;
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.started = false;
- this.dragging = false;
- this.start = null;
- this.last = null;
- deactivated = true;
- OpenLayers.Element.removeClass(
- this.map.viewPortDiv, "olDragDown"
- );
- }
- return deactivated;
- },
-
- /**
- * Method: adjustXY
- * Converts event coordinates that are relative to the document body to
- * ones that are relative to the map viewport. The latter is the default in
- * OpenLayers.
- *
- * Parameters:
- * evt - {Object}
- */
- adjustXY: function(evt) {
- var pos = OpenLayers.Util.pagePosition(this.map.viewPortDiv);
- evt.xy.x -= pos[0];
- evt.xy.y -= pos[1];
- },
-
- /**
- * Method: addDocumentEvents
- * Start observing document events when documentDrag is true and the mouse
- * cursor leaves the map viewport while dragging.
- */
- addDocumentEvents: function() {
- OpenLayers.Element.addClass(document.body, "olDragDown");
- this.documentEvents = true;
- OpenLayers.Event.observe(document, "mousemove", this._docMove);
- OpenLayers.Event.observe(document, "mouseup", this._docUp);
- },
-
- /**
- * Method: removeDocumentEvents
- * Stops observing document events when documentDrag is true and the mouse
- * cursor re-enters the map viewport while dragging.
- */
- removeDocumentEvents: function() {
- OpenLayers.Element.removeClass(document.body, "olDragDown");
- this.documentEvents = false;
- OpenLayers.Event.stopObserving(document, "mousemove", this._docMove);
- OpenLayers.Event.stopObserving(document, "mouseup", this._docUp);
- },
-
- CLASS_NAME: "OpenLayers.Handler.Drag"
-});
-/* ======================================================================
- OpenLayers/Handler/Keyboard.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Events.js
- */
-
-/**
- * Class: OpenLayers.handler.Keyboard
- * A handler for keyboard events. Create a new instance with the
- * <OpenLayers.Handler.Keyboard> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Keyboard = OpenLayers.Class(OpenLayers.Handler, {
-
- /* http://www.quirksmode.org/js/keys.html explains key x-browser
- key handling quirks in pretty nice detail */
-
- /**
- * Constant: KEY_EVENTS
- * keydown, keypress, keyup
- */
- KEY_EVENTS: ["keydown", "keyup"],
-
- /**
- * Property: eventListener
- * {Function}
- */
- eventListener: null,
-
- /**
- * Property: observeElement
- * {DOMElement|String} The DOM element on which we listen for
- * key events. Default to the document.
- */
- observeElement: null,
-
- /**
- * Constructor: OpenLayers.Handler.Keyboard
- * Returns a new keyboard handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handlers setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object containing a single function to be
- * called when the drag operation is finished. The callback should
- * expect to recieve a single argument, the pixel location of the event.
- * Callbacks for 'keydown', 'keypress', and 'keyup' are supported.
- * options - {Object} Optional object whose properties will be set on the
- * handler.
- */
- initialize: function(control, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- // cache the bound event listener method so it can be unobserved later
- this.eventListener = OpenLayers.Function.bindAsEventListener(
- this.handleKeyEvent, this
- );
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- this.deactivate();
- this.eventListener = null;
- OpenLayers.Handler.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: activate
- */
- activate: function() {
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.observeElement = this.observeElement || document;
- for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
- OpenLayers.Event.observe(
- this.observeElement, this.KEY_EVENTS[i], this.eventListener);
- }
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function() {
- var deactivated = false;
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- for (var i=0, len=this.KEY_EVENTS.length; i<len; i++) {
- OpenLayers.Event.stopObserving(
- this.observeElement, this.KEY_EVENTS[i], this.eventListener);
- }
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method: handleKeyEvent
- */
- handleKeyEvent: function (evt) {
- if (this.checkModifiers(evt)) {
- this.callback(evt.type, [evt]);
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.Keyboard"
-});
-/* ======================================================================
- OpenLayers/Control/ModifyFeature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- * @requires OpenLayers/Handler/Keyboard.js
- */
-
-/**
- * Class: OpenLayers.Control.ModifyFeature
- * Control to modify features. When activated, a click renders the vertices
- * of a feature - these vertices can then be dragged. By default, the
- * delete key will delete the vertex under the mouse. New features are
- * added by dragging "virtual vertices" between vertices. Create a new
- * control with the <OpenLayers.Control.ModifyFeature> constructor.
- *
- * Inherits From:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.ModifyFeature = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * APIProperty: documentDrag
- * {Boolean} If set to true, dragging vertices will continue even if the
- * mouse cursor leaves the map viewport. Default is false.
- */
- documentDrag: false,
-
- /**
- * APIProperty: geometryTypes
- * {Array(String)} To restrict modification to a limited set of geometry
- * types, send a list of strings corresponding to the geometry class
- * names.
- */
- geometryTypes: null,
-
- /**
- * APIProperty: clickout
- * {Boolean} Unselect features when clicking outside any feature.
- * Default is true.
- */
- clickout: true,
-
- /**
- * APIProperty: toggle
- * {Boolean} Unselect a selected feature on click.
- * Default is true.
- */
- toggle: true,
-
- /**
- * APIProperty: standalone
- * {Boolean} Set to true to create a control without SelectFeature
- * capabilities. Default is false. If standalone is true, to modify
- * a feature, call the <selectFeature> method with the target feature.
- * Note that you must call the <unselectFeature> method to finish
- * feature modification in standalone mode (before starting to modify
- * another feature).
- */
- standalone: false,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>}
- */
- layer: null,
-
- /**
- * Property: feature
- * {<OpenLayers.Feature.Vector>} Feature currently available for modification.
- */
- feature: null,
-
- /**
- * Property: vertex
- * {<OpenLayers.Feature.Vector>} Vertex currently being modified.
- */
- vertex: null,
-
- /**
- * Property: vertices
- * {Array(<OpenLayers.Feature.Vector>)} Verticies currently available
- * for dragging.
- */
- vertices: null,
-
- /**
- * Property: virtualVertices
- * {Array(<OpenLayers.Feature.Vector>)} Virtual vertices in the middle
- * of each edge.
- */
- virtualVertices: null,
-
- /**
- * Property: handlers
- * {Object}
- */
- handlers: null,
-
- /**
- * APIProperty: deleteCodes
- * {Array(Integer)} Keycodes for deleting verticies. Set to null to disable
- * vertex deltion by keypress. If non-null, keypresses with codes
- * in this array will delete vertices under the mouse. Default
- * is 46 and 68, the 'delete' and lowercase 'd' keys.
- */
- deleteCodes: null,
-
- /**
- * APIProperty: virtualStyle
- * {Object} A symbolizer to be used for virtual vertices.
- */
- virtualStyle: null,
-
- /**
- * APIProperty: vertexRenderIntent
- * {String} The renderIntent to use for vertices. If no <virtualStyle> is
- * provided, this renderIntent will also be used for virtual vertices, with
- * a fillOpacity and strokeOpacity of 0.3. Default is null, which means
- * that the layer's default style will be used for vertices.
- */
- vertexRenderIntent: null,
-
- /**
- * APIProperty: mode
- * {Integer} Bitfields specifying the modification mode. Defaults to
- * OpenLayers.Control.ModifyFeature.RESHAPE. To set the mode to a
- * combination of options, use the | operator. For example, to allow
- * the control to both resize and rotate features, use the following
- * syntax
- * (code)
- * control.mode = OpenLayers.Control.ModifyFeature.RESIZE |
- * OpenLayers.Control.ModifyFeature.ROTATE;
- * (end)
- */
- mode: null,
-
- /**
- * APIProperty: createVertices
- * {Boolean} Create new vertices by dragging the virtual vertices
- * in the middle of each edge. Default is true.
- */
- createVertices: true,
-
- /**
- * Property: modified
- * {Boolean} The currently selected feature has been modified.
- */
- modified: false,
-
- /**
- * Property: radiusHandle
- * {<OpenLayers.Feature.Vector>} A handle for rotating/resizing a feature.
- */
- radiusHandle: null,
-
- /**
- * Property: dragHandle
- * {<OpenLayers.Feature.Vector>} A handle for dragging a feature.
- */
- dragHandle: null,
-
- /**
- * APIProperty: onModificationStart
- * {Function} *Deprecated*. Register for "beforefeaturemodified" instead.
- * The "beforefeaturemodified" event is triggered on the layer before
- * any modification begins.
- *
- * Optional function to be called when a feature is selected
- * to be modified. The function should expect to be called with a
- * feature. This could be used for example to allow to lock the
- * feature on server-side.
- */
- onModificationStart: function() {},
-
- /**
- * APIProperty: onModification
- * {Function} *Deprecated*. Register for "featuremodified" instead.
- * The "featuremodified" event is triggered on the layer with each
- * feature modification.
- *
- * Optional function to be called when a feature has been
- * modified. The function should expect to be called with a feature.
- */
- onModification: function() {},
-
- /**
- * APIProperty: onModificationEnd
- * {Function} *Deprecated*. Register for "afterfeaturemodified" instead.
- * The "afterfeaturemodified" event is triggered on the layer after
- * a feature has been modified.
- *
- * Optional function to be called when a feature is finished
- * being modified. The function should expect to be called with a
- * feature.
- */
- onModificationEnd: function() {},
-
- /**
- * Constructor: OpenLayers.Control.ModifyFeature
- * Create a new modify feature control.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer.Vector>} Layer that contains features that
- * will be modified.
- * options - {Object} Optional object whose properties will be set on the
- * control.
- */
- initialize: function(layer, options) {
- options = options || {};
- this.layer = layer;
- this.vertices = [];
- this.virtualVertices = [];
- this.virtualStyle = OpenLayers.Util.extend({},
- this.layer.style ||
- this.layer.styleMap.createSymbolizer(null, options.vertexRenderIntent)
- );
- this.virtualStyle.fillOpacity = 0.3;
- this.virtualStyle.strokeOpacity = 0.3;
- this.deleteCodes = [46, 68];
- this.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- if(!(OpenLayers.Util.isArray(this.deleteCodes))) {
- this.deleteCodes = [this.deleteCodes];
- }
-
- // configure the drag handler
- var dragCallbacks = {
- down: function(pixel) {
- this.vertex = null;
- var feature = this.layer.getFeatureFromEvent(
- this.handlers.drag.evt);
- if (feature) {
- this.dragStart(feature);
- } else if (this.clickout) {
- this._unselect = this.feature;
- }
- },
- move: function(pixel) {
- delete this._unselect;
- if (this.vertex) {
- this.dragVertex(this.vertex, pixel);
- }
- },
- up: function() {
- this.handlers.drag.stopDown = false;
- if (this._unselect) {
- this.unselectFeature(this._unselect);
- delete this._unselect;
- }
- },
- done: function(pixel) {
- if (this.vertex) {
- this.dragComplete(this.vertex);
- }
- }
- };
- var dragOptions = {
- documentDrag: this.documentDrag,
- stopDown: false
- };
-
- // configure the keyboard handler
- var keyboardOptions = {
- keydown: this.handleKeypress
- };
- this.handlers = {
- keyboard: new OpenLayers.Handler.Keyboard(this, keyboardOptions),
- drag: new OpenLayers.Handler.Drag(this, dragCallbacks, dragOptions)
- };
- },
-
- /**
- * APIMethod: destroy
- * Take care of things that are not handled in superclass.
- */
- destroy: function() {
- if (this.map) {
- this.map.events.un({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- }
- this.layer = null;
- OpenLayers.Control.prototype.destroy.apply(this, []);
- },
-
- /**
- * APIMethod: activate
- * Activate the control.
- *
- * Returns:
- * {Boolean} Successfully activated the control.
- */
- activate: function() {
- this.moveLayerToTop();
- this.map.events.on({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- return (this.handlers.keyboard.activate() &&
- this.handlers.drag.activate() &&
- OpenLayers.Control.prototype.activate.apply(this, arguments));
- },
-
- /**
- * APIMethod: deactivate
- * Deactivate the control.
- *
- * Returns:
- * {Boolean} Successfully deactivated the control.
- */
- deactivate: function() {
- var deactivated = false;
- // the return from the controls is unimportant in this case
- if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
- this.moveLayerBack();
- this.map.events.un({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- this.layer.removeFeatures(this.vertices, {silent: true});
- this.layer.removeFeatures(this.virtualVertices, {silent: true});
- this.vertices = [];
- this.handlers.drag.deactivate();
- this.handlers.keyboard.deactivate();
- var feature = this.feature;
- if (feature && feature.geometry && feature.layer) {
- this.unselectFeature(feature);
- }
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method: beforeSelectFeature
- * Called before a feature is selected.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} The feature about to be selected.
- */
- beforeSelectFeature: function(feature) {
- return this.layer.events.triggerEvent(
- "beforefeaturemodified", {feature: feature}
- );
- },
-
- /**
- * APIMethod: selectFeature
- * Select a feature for modification in standalone mode. In non-standalone
- * mode, this method is called when a feature is selected by clicking.
- * Register a listener to the beforefeaturemodified event and return false
- * to prevent feature modification.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} the selected feature.
- */
- selectFeature: function(feature) {
- if (this.feature === feature ||
- (this.geometryTypes && OpenLayers.Util.indexOf(this.geometryTypes,
- feature.geometry.CLASS_NAME) == -1)) {
- return;
- }
- if (this.beforeSelectFeature(feature) !== false) {
- if (this.feature) {
- this.unselectFeature(this.feature);
- }
- this.feature = feature;
- this.layer.selectedFeatures.push(feature);
- this.layer.drawFeature(feature, 'select');
- this.modified = false;
- this.resetVertices();
- this.onModificationStart(this.feature);
- }
- // keep track of geometry modifications
- var modified = feature.modified;
- if (feature.geometry && !(modified && modified.geometry)) {
- this._originalGeometry = feature.geometry.clone();
- }
- },
-
- /**
- * APIMethod: unselectFeature
- * Called when the select feature control unselects a feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} The unselected feature.
- */
- unselectFeature: function(feature) {
- this.layer.removeFeatures(this.vertices, {silent: true});
- this.vertices = [];
- this.layer.destroyFeatures(this.virtualVertices, {silent: true});
- this.virtualVertices = [];
- if(this.dragHandle) {
- this.layer.destroyFeatures([this.dragHandle], {silent: true});
- delete this.dragHandle;
- }
- if(this.radiusHandle) {
- this.layer.destroyFeatures([this.radiusHandle], {silent: true});
- delete this.radiusHandle;
- }
- this.layer.drawFeature(this.feature, 'default');
- this.feature = null;
- OpenLayers.Util.removeItem(this.layer.selectedFeatures, feature);
- this.onModificationEnd(feature);
- this.layer.events.triggerEvent("afterfeaturemodified", {
- feature: feature,
- modified: this.modified
- });
- this.modified = false;
- },
-
-
- /**
- * Method: dragStart
- * Called by the drag handler before a feature is dragged. This method is
- * used to differentiate between points and vertices
- * of higher order geometries.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} The point or vertex about to be
- * dragged.
- */
- dragStart: function(feature) {
- var isPoint = feature.geometry.CLASS_NAME ==
- 'OpenLayers.Geometry.Point';
- if (!this.standalone &&
- ((!feature._sketch && isPoint) || !feature._sketch)) {
- if (this.toggle && this.feature === feature) {
- // mark feature for unselection
- this._unselect = feature;
- }
- this.selectFeature(feature);
- }
- if (feature._sketch || isPoint) {
- // feature is a drag or virtual handle or point
- this.vertex = feature;
- this.handlers.drag.stopDown = true;
- }
- },
-
- /**
- * Method: dragVertex
- * Called by the drag handler with each drag move of a vertex.
- *
- * Parameters:
- * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
- * pixel - {<OpenLayers.Pixel>} Pixel location of the mouse event.
- */
- dragVertex: function(vertex, pixel) {
- var pos = this.map.getLonLatFromViewPortPx(pixel);
- var geom = vertex.geometry;
- geom.move(pos.lon - geom.x, pos.lat - geom.y);
- this.modified = true;
- /**
- * Five cases:
- * 1) dragging a simple point
- * 2) dragging a virtual vertex
- * 3) dragging a drag handle
- * 4) dragging a real vertex
- * 5) dragging a radius handle
- */
- if(this.feature.geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- // dragging a simple point
- this.layer.events.triggerEvent("vertexmodified", {
- vertex: vertex.geometry,
- feature: this.feature,
- pixel: pixel
- });
- } else {
- if(vertex._index) {
- // dragging a virtual vertex
- vertex.geometry.parent.addComponent(vertex.geometry,
- vertex._index);
- // move from virtual to real vertex
- delete vertex._index;
- OpenLayers.Util.removeItem(this.virtualVertices, vertex);
- this.vertices.push(vertex);
- } else if(vertex == this.dragHandle) {
- // dragging a drag handle
- this.layer.removeFeatures(this.vertices, {silent: true});
- this.vertices = [];
- if(this.radiusHandle) {
- this.layer.destroyFeatures([this.radiusHandle], {silent: true});
- this.radiusHandle = null;
- }
- } else if(vertex !== this.radiusHandle) {
- // dragging a real vertex
- this.layer.events.triggerEvent("vertexmodified", {
- vertex: vertex.geometry,
- feature: this.feature,
- pixel: pixel
- });
- }
- // dragging a radius handle - no special treatment
- if(this.virtualVertices.length > 0) {
- this.layer.destroyFeatures(this.virtualVertices, {silent: true});
- this.virtualVertices = [];
- }
- this.layer.drawFeature(this.feature, this.standalone ? undefined :
- 'select');
- }
- // keep the vertex on top so it gets the mouseout after dragging
- // this should be removed in favor of an option to draw under or
- // maintain node z-index
- this.layer.drawFeature(vertex);
- },
-
- /**
- * Method: dragComplete
- * Called by the drag handler when the feature dragging is complete.
- *
- * Parameters:
- * vertex - {<OpenLayers.Feature.Vector>} The vertex being dragged.
- */
- dragComplete: function(vertex) {
- this.resetVertices();
- this.setFeatureState();
- this.onModification(this.feature);
- this.layer.events.triggerEvent("featuremodified",
- {feature: this.feature});
- },
-
- /**
- * Method: setFeatureState
- * Called when the feature is modified. If the current state is not
- * INSERT or DELETE, the state is set to UPDATE.
- */
- setFeatureState: function() {
- if(this.feature.state != OpenLayers.State.INSERT &&
- this.feature.state != OpenLayers.State.DELETE) {
- this.feature.state = OpenLayers.State.UPDATE;
- if (this.modified && this._originalGeometry) {
- var feature = this.feature;
- feature.modified = OpenLayers.Util.extend(feature.modified, {
- geometry: this._originalGeometry
- });
- delete this._originalGeometry;
- }
- }
- },
-
- /**
- * Method: resetVertices
- */
- resetVertices: function() {
- if(this.vertices.length > 0) {
- this.layer.removeFeatures(this.vertices, {silent: true});
- this.vertices = [];
- }
- if(this.virtualVertices.length > 0) {
- this.layer.removeFeatures(this.virtualVertices, {silent: true});
- this.virtualVertices = [];
- }
- if(this.dragHandle) {
- this.layer.destroyFeatures([this.dragHandle], {silent: true});
- this.dragHandle = null;
- }
- if(this.radiusHandle) {
- this.layer.destroyFeatures([this.radiusHandle], {silent: true});
- this.radiusHandle = null;
- }
- if(this.feature &&
- this.feature.geometry.CLASS_NAME != "OpenLayers.Geometry.Point") {
- if((this.mode & OpenLayers.Control.ModifyFeature.DRAG)) {
- this.collectDragHandle();
- }
- if((this.mode & (OpenLayers.Control.ModifyFeature.ROTATE |
- OpenLayers.Control.ModifyFeature.RESIZE))) {
- this.collectRadiusHandle();
- }
- if(this.mode & OpenLayers.Control.ModifyFeature.RESHAPE){
- // Don't collect vertices when we're resizing
- if (!(this.mode & OpenLayers.Control.ModifyFeature.RESIZE)){
- this.collectVertices();
- }
- }
- }
- },
-
- /**
- * Method: handleKeypress
- * Called by the feature handler on keypress. This is used to delete
- * vertices. If the <deleteCode> property is set, vertices will
- * be deleted when a feature is selected for modification and
- * the mouse is over a vertex.
- *
- * Parameters:
- * evt - {Event} Keypress event.
- */
- handleKeypress: function(evt) {
- var code = evt.keyCode;
-
- // check for delete key
- if(this.feature &&
- OpenLayers.Util.indexOf(this.deleteCodes, code) != -1) {
- var vertex = this.layer.getFeatureFromEvent(this.handlers.drag.evt);
- if (vertex &&
- OpenLayers.Util.indexOf(this.vertices, vertex) != -1 &&
- !this.handlers.drag.dragging && vertex.geometry.parent) {
- // remove the vertex
- vertex.geometry.parent.removeComponent(vertex.geometry);
- this.layer.events.triggerEvent("vertexremoved", {
- vertex: vertex.geometry,
- feature: this.feature,
- pixel: evt.xy
- });
- this.layer.drawFeature(this.feature, this.standalone ?
- undefined : 'select');
- this.modified = true;
- this.resetVertices();
- this.setFeatureState();
- this.onModification(this.feature);
- this.layer.events.triggerEvent("featuremodified",
- {feature: this.feature});
- }
- }
- },
-
- /**
- * Method: collectVertices
- * Collect the vertices from the modifiable feature's geometry and push
- * them on to the control's vertices array.
- */
- collectVertices: function() {
- this.vertices = [];
- this.virtualVertices = [];
- var control = this;
- function collectComponentVertices(geometry) {
- var i, vertex, component, len;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- vertex = new OpenLayers.Feature.Vector(geometry);
- vertex._sketch = true;
- vertex.renderIntent = control.vertexRenderIntent;
- control.vertices.push(vertex);
- } else {
- var numVert = geometry.components.length;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
- numVert -= 1;
- }
- for(i=0; i<numVert; ++i) {
- component = geometry.components[i];
- if(component.CLASS_NAME == "OpenLayers.Geometry.Point") {
- vertex = new OpenLayers.Feature.Vector(component);
- vertex._sketch = true;
- vertex.renderIntent = control.vertexRenderIntent;
- control.vertices.push(vertex);
- } else {
- collectComponentVertices(component);
- }
- }
-
- // add virtual vertices in the middle of each edge
- if (control.createVertices && geometry.CLASS_NAME != "OpenLayers.Geometry.MultiPoint") {
- for(i=0, len=geometry.components.length; i<len-1; ++i) {
- var prevVertex = geometry.components[i];
- var nextVertex = geometry.components[i + 1];
- if(prevVertex.CLASS_NAME == "OpenLayers.Geometry.Point" &&
- nextVertex.CLASS_NAME == "OpenLayers.Geometry.Point") {
- var x = (prevVertex.x + nextVertex.x) / 2;
- var y = (prevVertex.y + nextVertex.y) / 2;
- var point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(x, y),
- null, control.virtualStyle
- );
- // set the virtual parent and intended index
- point.geometry.parent = geometry;
- point._index = i + 1;
- point._sketch = true;
- control.virtualVertices.push(point);
- }
- }
- }
- }
- }
- collectComponentVertices.call(this, this.feature.geometry);
- this.layer.addFeatures(this.virtualVertices, {silent: true});
- this.layer.addFeatures(this.vertices, {silent: true});
- },
-
- /**
- * Method: collectDragHandle
- * Collect the drag handle for the selected geometry.
- */
- collectDragHandle: function() {
- var geometry = this.feature.geometry;
- var center = geometry.getBounds().getCenterLonLat();
- var originGeometry = new OpenLayers.Geometry.Point(
- center.lon, center.lat
- );
- var origin = new OpenLayers.Feature.Vector(originGeometry);
- originGeometry.move = function(x, y) {
- OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
- geometry.move(x, y);
- };
- origin._sketch = true;
- this.dragHandle = origin;
- this.dragHandle.renderIntent = this.vertexRenderIntent;
- this.layer.addFeatures([this.dragHandle], {silent: true});
- },
-
- /**
- * Method: collectRadiusHandle
- * Collect the radius handle for the selected geometry.
- */
- collectRadiusHandle: function() {
- var geometry = this.feature.geometry;
- var bounds = geometry.getBounds();
- var center = bounds.getCenterLonLat();
- var originGeometry = new OpenLayers.Geometry.Point(
- center.lon, center.lat
- );
- var radiusGeometry = new OpenLayers.Geometry.Point(
- bounds.right, bounds.bottom
- );
- var radius = new OpenLayers.Feature.Vector(radiusGeometry);
- var resize = (this.mode & OpenLayers.Control.ModifyFeature.RESIZE);
- var reshape = (this.mode & OpenLayers.Control.ModifyFeature.RESHAPE);
- var rotate = (this.mode & OpenLayers.Control.ModifyFeature.ROTATE);
-
- radiusGeometry.move = function(x, y) {
- OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
- var dx1 = this.x - originGeometry.x;
- var dy1 = this.y - originGeometry.y;
- var dx0 = dx1 - x;
- var dy0 = dy1 - y;
- if(rotate) {
- var a0 = Math.atan2(dy0, dx0);
- var a1 = Math.atan2(dy1, dx1);
- var angle = a1 - a0;
- angle *= 180 / Math.PI;
- geometry.rotate(angle, originGeometry);
- }
- if(resize) {
- var scale, ratio;
- // 'resize' together with 'reshape' implies that the aspect
- // ratio of the geometry will not be preserved whilst resizing
- if (reshape) {
- scale = dy1 / dy0;
- ratio = (dx1 / dx0) / scale;
- } else {
- var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0));
- var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
- scale = l1 / l0;
- }
- geometry.resize(scale, originGeometry, ratio);
- }
- };
- radius._sketch = true;
- this.radiusHandle = radius;
- this.radiusHandle.renderIntent = this.vertexRenderIntent;
- this.layer.addFeatures([this.radiusHandle], {silent: true});
- },
-
- /**
- * Method: setMap
- * Set the map property for the control and all handlers.
- *
- * Parameters:
- * map - {<OpenLayers.Map>} The control's map.
- */
- setMap: function(map) {
- this.handlers.drag.setMap(map);
- OpenLayers.Control.prototype.setMap.apply(this, arguments);
- },
-
- /**
- * Method: handleMapEvents
- *
- * Parameters:
- * evt - {Object}
- */
- handleMapEvents: function(evt) {
- if (evt.type == "removelayer" || evt.property == "order") {
- this.moveLayerToTop();
- }
- },
-
- /**
- * Method: moveLayerToTop
- * Moves the layer for this handler to the top, so mouse events can reach
- * it.
- */
- moveLayerToTop: function() {
- var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
- this.layer.getZIndex()) + 1;
- this.layer.setZIndex(index);
-
- },
-
- /**
- * Method: moveLayerBack
- * Moves the layer back to the position determined by the map's layers
- * array.
- */
- moveLayerBack: function() {
- var index = this.layer.getZIndex() - 1;
- if (index >= this.map.Z_INDEX_BASE['Feature']) {
- this.layer.setZIndex(index);
- } else {
- this.map.setLayerZIndex(this.layer,
- this.map.getLayerIndex(this.layer));
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.ModifyFeature"
-});
-
-/**
- * Constant: RESHAPE
- * {Integer} Constant used to make the control work in reshape mode
- */
-OpenLayers.Control.ModifyFeature.RESHAPE = 1;
-/**
- * Constant: RESIZE
- * {Integer} Constant used to make the control work in resize mode
- */
-OpenLayers.Control.ModifyFeature.RESIZE = 2;
-/**
- * Constant: ROTATE
- * {Integer} Constant used to make the control work in rotate mode
- */
-OpenLayers.Control.ModifyFeature.ROTATE = 4;
-/**
- * Constant: DRAG
- * {Integer} Constant used to make the control work in drag mode
- */
-OpenLayers.Control.ModifyFeature.DRAG = 8;
-/* ======================================================================
- OpenLayers/Layer/Bing.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/XYZ.js
- */
-
-/**
- * Class: OpenLayers.Layer.Bing
- * Bing layer using direct tile access as provided by Bing Maps REST Services.
- * See http://msdn.microsoft.com/en-us/library/ff701713.aspx for more
- * information. Note: Terms of Service compliant use requires the map to be
- * configured with an <OpenLayers.Control.Attribution> control and the
- * attribution placed on or near the map.
- *
- * Inherits from:
- * - <OpenLayers.Layer.XYZ>
- */
-OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, {
-
- /**
- * Property: key
- * {String} API key for Bing maps, get your own key
- * at http://bingmapsportal.com/ .
- */
- key: null,
-
- /**
- * Property: serverResolutions
- * {Array} the resolutions provided by the Bing servers.
- */
- serverResolutions: [
- 156543.03390625, 78271.516953125, 39135.7584765625,
- 19567.87923828125, 9783.939619140625, 4891.9698095703125,
- 2445.9849047851562, 1222.9924523925781, 611.4962261962891,
- 305.74811309814453, 152.87405654907226, 76.43702827453613,
- 38.218514137268066, 19.109257068634033, 9.554628534317017,
- 4.777314267158508, 2.388657133579254, 1.194328566789627,
- 0.5971642833948135, 0.29858214169740677, 0.14929107084870338,
- 0.07464553542435169
- ],
-
- /**
- * Property: attributionTemplate
- * {String}
- */
- attributionTemplate: '<span class="olBingAttribution ${type}">' +
- '<div><a target="_blank" href="http://www.bing.com/maps/">' +
- '<img src="${logo}" /></a></div>${copyrights}' +
- '<a style="white-space: nowrap" target="_blank" '+
- 'href="http://www.microsoft.com/maps/product/terms.html">' +
- 'Terms of Use</a></span>',
-
- /**
- * Property: metadata
- * {Object} Metadata for this layer, as returned by the callback script
- */
- metadata: null,
-
- /**
- * Property: protocolRegex
- * {RegExp} Regular expression to match and replace http: in bing urls
- */
- protocolRegex: /^http:/i,
-
- /**
- * APIProperty: type
- * {String} The layer identifier. Any non-birdseye imageryType
- * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be
- * used. Default is "Road".
- */
- type: "Road",
-
- /**
- * APIProperty: culture
- * {String} The culture identifier. See http://msdn.microsoft.com/en-us/library/ff701709.aspx
- * for the definition and the possible values. Default is "en-US".
- */
- culture: "en-US",
-
- /**
- * APIProperty: metadataParams
- * {Object} Optional url parameters for the Get Imagery Metadata request
- * as described here: http://msdn.microsoft.com/en-us/library/ff701716.aspx
- */
- metadataParams: null,
-
- /** APIProperty: tileOptions
- * {Object} optional configuration options for <OpenLayers.Tile> instances
- * created by this Layer. Default is
- *
- * (code)
- * {crossOriginKeyword: 'anonymous'}
- * (end)
- */
- tileOptions: null,
-
- /** APIProperty: protocol
- * {String} Protocol to use to fetch Imagery Metadata, tiles and bing logo
- * Can be 'http:' 'https:' or ''
- *
- * Warning: tiles may not be available under both HTTP and HTTPS protocols.
- * Microsoft approved use of both HTTP and HTTPS urls for tiles. However
- * this is undocumented and the Imagery Metadata API always returns HTTP
- * urls.
- *
- * Default is '', unless when executed from a file:/// uri, in which case
- * it is 'http:'.
- */
- protocol: ~window.location.href.indexOf('http') ? '' : 'http:',
-
- /**
- * Constructor: OpenLayers.Layer.Bing
- * Create a new Bing layer.
- *
- * Example:
- * (code)
- * var road = new OpenLayers.Layer.Bing({
- * name: "My Bing Aerial Layer",
- * type: "Aerial",
- * key: "my-api-key-here",
- * });
- * (end)
- *
- * Parameters:
- * options - {Object} Configuration properties for the layer.
- *
- * Required configuration properties:
- * key - {String} Bing Maps API key for your application. Get one at
- * http://bingmapsportal.com/.
- * type - {String} The layer identifier. Any non-birdseye imageryType
- * from http://msdn.microsoft.com/en-us/library/ff701716.aspx can be
- * used.
- *
- * Any other documented layer properties can be provided in the config object.
- */
- initialize: function(options) {
- options = OpenLayers.Util.applyDefaults({
- sphericalMercator: true
- }, options);
- var name = options.name || "Bing " + (options.type || this.type);
-
- var newArgs = [name, null, options];
- OpenLayers.Layer.XYZ.prototype.initialize.apply(this, newArgs);
- this.tileOptions = OpenLayers.Util.extend({
- crossOriginKeyword: 'anonymous'
- }, this.options.tileOptions);
- this.loadMetadata();
- },
-
- /**
- * Method: loadMetadata
- */
- loadMetadata: function() {
- this._callbackId = "_callback_" + this.id.replace(/\./g, "_");
- // link the processMetadata method to the global scope and bind it
- // to this instance
- window[this._callbackId] = OpenLayers.Function.bind(
- OpenLayers.Layer.Bing.processMetadata, this
- );
- var params = OpenLayers.Util.applyDefaults({
- key: this.key,
- jsonp: this._callbackId,
- include: "ImageryProviders"
- }, this.metadataParams);
- var url = this.protocol + "//dev.virtualearth.net/REST/v1/Imagery/Metadata/" +
- this.type + "?" + OpenLayers.Util.getParameterString(params);
- var script = document.createElement("script");
- script.type = "text/javascript";
- script.src = url;
- script.id = this._callbackId;
- document.getElementsByTagName("head")[0].appendChild(script);
- },
-
- /**
- * Method: initLayer
- *
- * Sets layer properties according to the metadata provided by the API
- */
- initLayer: function() {
- var res = this.metadata.resourceSets[0].resources[0];
- var url = res.imageUrl.replace("{quadkey}", "${quadkey}");
- url = url.replace("{culture}", this.culture);
- url = url.replace(this.protocolRegex, this.protocol);
- this.url = [];
- for (var i=0; i<res.imageUrlSubdomains.length; ++i) {
- this.url.push(url.replace("{subdomain}", res.imageUrlSubdomains[i]));
- }
- this.addOptions({
- maxResolution: Math.min(
- this.serverResolutions[res.zoomMin],
- this.maxResolution || Number.POSITIVE_INFINITY
- ),
- numZoomLevels: Math.min(
- res.zoomMax + 1 - res.zoomMin, this.numZoomLevels
- )
- }, true);
- if (!this.isBaseLayer) {
- this.redraw();
- }
- this.updateAttribution();
- },
-
- /**
- * Method: getURL
- *
- * Paramters:
- * bounds - {<OpenLayers.Bounds>}
- */
- getURL: function(bounds) {
- if (!this.url) {
- return;
- }
- var xyz = this.getXYZ(bounds), x = xyz.x, y = xyz.y, z = xyz.z;
- var quadDigits = [];
- for (var i = z; i > 0; --i) {
- var digit = '0';
- var mask = 1 << (i - 1);
- if ((x & mask) != 0) {
- digit++;
- }
- if ((y & mask) != 0) {
- digit++;
- digit++;
- }
- quadDigits.push(digit);
- }
- var quadKey = quadDigits.join("");
- var url = this.selectUrl('' + x + y + z, this.url);
-
- return OpenLayers.String.format(url, {'quadkey': quadKey});
- },
-
- /**
- * Method: updateAttribution
- * Updates the attribution according to the requirements outlined in
- * http://gis.638310.n2.nabble.com/Bing-imagery-td5789168.html
- */
- updateAttribution: function() {
- var metadata = this.metadata;
- if (!metadata.resourceSets || !this.map || !this.map.center) {
- return;
- }
- var res = metadata.resourceSets[0].resources[0];
- var extent = this.map.getExtent().transform(
- this.map.getProjectionObject(),
- new OpenLayers.Projection("EPSG:4326")
- );
- var providers = res.imageryProviders || [],
- zoom = OpenLayers.Util.indexOf(this.serverResolutions,
- this.getServerResolution()),
- copyrights = "", provider, i, ii, j, jj, bbox, coverage;
- for (i=0,ii=providers.length; i<ii; ++i) {
- provider = providers[i];
- for (j=0,jj=provider.coverageAreas.length; j<jj; ++j) {
- coverage = provider.coverageAreas[j];
- // axis order provided is Y,X
- bbox = OpenLayers.Bounds.fromArray(coverage.bbox, true);
- if (extent.intersectsBounds(bbox) &&
- zoom <= coverage.zoomMax && zoom >= coverage.zoomMin) {
- copyrights += provider.attribution + " ";
- }
- }
- }
- var logo = metadata.brandLogoUri.replace(this.protocolRegex, this.protocol);
- this.attribution = OpenLayers.String.format(this.attributionTemplate, {
- type: this.type.toLowerCase(),
- logo: logo,
- copyrights: copyrights
- });
- this.map && this.map.events.triggerEvent("changelayer", {
- layer: this,
- property: "attribution"
- });
- },
-
- /**
- * Method: setMap
- */
- setMap: function() {
- OpenLayers.Layer.XYZ.prototype.setMap.apply(this, arguments);
- this.map.events.register("moveend", this, this.updateAttribution);
- },
-
- /**
- * APIMethod: clone
- *
- * Parameters:
- * obj - {Object}
- *
- * Returns:
- * {<OpenLayers.Layer.Bing>} An exact clone of this <OpenLayers.Layer.Bing>
- */
- clone: function(obj) {
- if (obj == null) {
- obj = new OpenLayers.Layer.Bing(this.options);
- }
- //get all additions from superclasses
- obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
- // copy/set any non-init, non-simple values here
- return obj;
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- this.map &&
- this.map.events.unregister("moveend", this, this.updateAttribution);
- OpenLayers.Layer.XYZ.prototype.destroy.apply(this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Layer.Bing"
-});
-
-/**
- * Function: OpenLayers.Layer.Bing.processMetadata
- * This function will be bound to an instance, linked to the global scope with
- * an id, and called by the JSONP script returned by the API.
- *
- * Parameters:
- * metadata - {Object} metadata as returned by the API
- */
-OpenLayers.Layer.Bing.processMetadata = function(metadata) {
- this.metadata = metadata;
- this.initLayer();
- var script = document.getElementById(this._callbackId);
- script.parentNode.removeChild(script);
- window[this._callbackId] = undefined; // cannot delete from window in IE
- delete this._callbackId;
-};
-/* ======================================================================
- OpenLayers/Geometry/MultiLineString.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Geometry/LineString.js
- */
-
-/**
- * Class: OpenLayers.Geometry.MultiLineString
- * A MultiLineString is a geometry with multiple <OpenLayers.Geometry.LineString>
- * components.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Collection>
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.MultiLineString = OpenLayers.Class(
- OpenLayers.Geometry.Collection, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.LineString"],
-
- /**
- * Constructor: OpenLayers.Geometry.MultiLineString
- * Constructor for a MultiLineString Geometry.
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.LineString>)}
- *
- */
-
- /**
- * Method: split
- * Use this geometry (the source) to attempt to split a target geometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- split: function(geometry, options) {
- var results = null;
- var mutual = options && options.mutual;
- var splits, sourceLine, sourceLines, sourceSplit, targetSplit;
- var sourceParts = [];
- var targetParts = [geometry];
- for(var i=0, len=this.components.length; i<len; ++i) {
- sourceLine = this.components[i];
- sourceSplit = false;
- for(var j=0; j < targetParts.length; ++j) {
- splits = sourceLine.split(targetParts[j], options);
- if(splits) {
- if(mutual) {
- sourceLines = splits[0];
- for(var k=0, klen=sourceLines.length; k<klen; ++k) {
- if(k===0 && sourceParts.length) {
- sourceParts[sourceParts.length-1].addComponent(
- sourceLines[k]
- );
- } else {
- sourceParts.push(
- new OpenLayers.Geometry.MultiLineString([
- sourceLines[k]
- ])
- );
- }
- }
- sourceSplit = true;
- splits = splits[1];
- }
- if(splits.length) {
- // splice in new target parts
- splits.unshift(j, 1);
- Array.prototype.splice.apply(targetParts, splits);
- break;
- }
- }
- }
- if(!sourceSplit) {
- // source line was not hit
- if(sourceParts.length) {
- // add line to existing multi
- sourceParts[sourceParts.length-1].addComponent(
- sourceLine.clone()
- );
- } else {
- // create a fresh multi
- sourceParts = [
- new OpenLayers.Geometry.MultiLineString(
- sourceLine.clone()
- )
- ];
- }
- }
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceSplit || targetSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- /**
- * Method: splitWith
- * Split this geometry (the target) with the given geometry (the source).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} A geometry used to split this
- * geometry (the source).
- * options - {Object} Properties of this object will be used to determine
- * how the split is conducted.
- *
- * Valid options:
- * mutual - {Boolean} Split the source geometry in addition to the target
- * geometry. Default is false.
- * edge - {Boolean} Allow splitting when only edges intersect. Default is
- * true. If false, a vertex on the source must be within the tolerance
- * distance of the intersection to be considered a split.
- * tolerance - {Number} If a non-null value is provided, intersections
- * within the tolerance distance of an existing vertex on the source
- * will be assumed to occur at the vertex.
- *
- * Returns:
- * {Array} A list of geometries (of this same type as the target) that
- * result from splitting the target with the source geometry. The
- * source and target geometry will remain unmodified. If no split
- * results, null will be returned. If mutual is true and a split
- * results, return will be an array of two arrays - the first will be
- * all geometries that result from splitting the source geometry and
- * the second will be all geometries that result from splitting the
- * target geometry.
- */
- splitWith: function(geometry, options) {
- var results = null;
- var mutual = options && options.mutual;
- var splits, targetLine, sourceLines, sourceSplit, targetSplit, sourceParts, targetParts;
- if(geometry instanceof OpenLayers.Geometry.LineString) {
- targetParts = [];
- sourceParts = [geometry];
- for(var i=0, len=this.components.length; i<len; ++i) {
- targetSplit = false;
- targetLine = this.components[i];
- for(var j=0; j<sourceParts.length; ++j) {
- splits = sourceParts[j].split(targetLine, options);
- if(splits) {
- if(mutual) {
- sourceLines = splits[0];
- if(sourceLines.length) {
- // splice in new source parts
- sourceLines.unshift(j, 1);
- Array.prototype.splice.apply(sourceParts, sourceLines);
- j += sourceLines.length - 2;
- }
- splits = splits[1];
- if(splits.length === 0) {
- splits = [targetLine.clone()];
- }
- }
- for(var k=0, klen=splits.length; k<klen; ++k) {
- if(k===0 && targetParts.length) {
- targetParts[targetParts.length-1].addComponent(
- splits[k]
- );
- } else {
- targetParts.push(
- new OpenLayers.Geometry.MultiLineString([
- splits[k]
- ])
- );
- }
- }
- targetSplit = true;
- }
- }
- if(!targetSplit) {
- // target component was not hit
- if(targetParts.length) {
- // add it to any existing multi-line
- targetParts[targetParts.length-1].addComponent(
- targetLine.clone()
- );
- } else {
- // or start with a fresh multi-line
- targetParts = [
- new OpenLayers.Geometry.MultiLineString([
- targetLine.clone()
- ])
- ];
- }
-
- }
- }
- } else {
- results = geometry.split(this);
- }
- if(sourceParts && sourceParts.length > 1) {
- sourceSplit = true;
- } else {
- sourceParts = [];
- }
- if(targetParts && targetParts.length > 1) {
- targetSplit = true;
- } else {
- targetParts = [];
- }
- if(sourceSplit || targetSplit) {
- if(mutual) {
- results = [sourceParts, targetParts];
- } else {
- results = targetParts;
- }
- }
- return results;
- },
-
- CLASS_NAME: "OpenLayers.Geometry.MultiLineString"
-});
-/* ======================================================================
- OpenLayers/Format.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/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/XML.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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: createDocumentFragment
- * Create a document fragment node that can be appended to another node
- * created by createElementNS. This will call
- * document.createDocumentFragment outside of IE. In IE, the ActiveX
- * object's createDocumentFragment method is used.
- *
- * Returns:
- * {Element} A document fragment.
- */
- createDocumentFragment: function() {
- var element;
- if (this.xmldom) {
- element = this.xmldom.createDocumentFragment();
- } else {
- element = document.createDocumentFragment();
- }
- 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/OGCExceptionReport.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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.
- *
- * To enable checking if parsing succeeded, you will need to define a property
- * called errorProperty on the parser you want to check. The parser will then
- * check the returned object to see if that property is present. If it is, it
- * assumes the parsing was successful. If it is not present (or is null), it will
- * pass the document through an OGCExceptionReport parser.
- *
- * If errorProperty is undefined for the parser, this error checking mechanism
- * will be disabled.
- *
- *
- *
- * 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: allowFallback
- * {Boolean} If a profiled parser cannot be found for the returned version,
- * use a non-profiled parser as the fallback. Application code using this
- * should take into account that the return object structure might be
- * missing the specifics of the profile. Defaults to false.
- */
- allowFallback: false,
-
- /**
- * 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) {
- if (profile !== "" && this.allowFallback) {
- // fallback to the non-profiled version of the parser
- profile = "";
- format = OpenLayers.Format[this.name][
- "v" + version.replace(/\./g, "_")
- ];
- }
- 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); // Select the parser
- var obj = this.parser.read(data, options); // Parse the data
-
- var errorProperty = this.parser.errorProperty || null;
- if (errorProperty !== null && obj[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-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/BaseTypes/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: id
- * {String}
- */
- id: null,
-
- /**
- * Property: lonlat
- * {<OpenLayers.LonLat>}
- */
- lonlat: null,
-
- /**
- * Property: data
- * {Object}
- */
- data: null,
-
- /**
- * Property: marker
- * {<OpenLayers.Marker>}
- */
- marker: null,
-
- /**
- * APIProperty: popupClass
- * {<OpenLayers.Class>} The class which will be used to instantiate
- * a new Popup. Default is <OpenLayers.Popup.Anchored>.
- */
- popupClass: null,
-
- /**
- * Property: popup
- * {<OpenLayers.Popup>}
- */
- popup: null,
-
- /**
- * Constructor: OpenLayers.Feature
- * Constructor for features.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer>}
- * lonlat - {<OpenLayers.LonLat>}
- * data - {Object}
- *
- * Returns:
- * {<OpenLayers.Feature>}
- */
- initialize: function(layer, lonlat, data) {
- this.layer = layer;
- this.lonlat = lonlat;
- this.data = (data != null) ? data : {};
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * Method: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
-
- //remove the popup from the map
- if ((this.layer != null) && (this.layer.map != null)) {
- if (this.popup != null) {
- this.layer.map.removePopup(this.popup);
- }
- }
- // remove the marker from the layer
- if (this.layer != null && this.marker != null) {
- this.layer.removeMarker(this.marker);
- }
-
- this.layer = null;
- this.id = null;
- this.lonlat = null;
- this.data = null;
- if (this.marker != null) {
- this.destroyMarker(this.marker);
- this.marker = null;
- }
- if (this.popup != null) {
- this.destroyPopup(this.popup);
- this.popup = null;
- }
- },
-
- /**
- * Method: onScreen
- *
- * Returns:
- * {Boolean} Whether or not the feature is currently visible on screen
- * (based on its 'lonlat' property)
- */
- onScreen:function() {
-
- var onScreen = false;
- if ((this.layer != null) && (this.layer.map != null)) {
- var screenBounds = this.layer.map.getExtent();
- onScreen = screenBounds.containsLonLat(this.lonlat);
- }
- return onScreen;
- },
-
-
- /**
- * Method: createMarker
- * Based on the data associated with the Feature, create and return a marker object.
- *
- * Returns:
- * {<OpenLayers.Marker>} A Marker Object created from the 'lonlat' and 'icon' properties
- * set in this.data. If no 'lonlat' is set, returns null. If no
- * 'icon' is set, OpenLayers.Marker() will load the default image.
- *
- * Note - this.marker is set to return value
- *
- */
- createMarker: function() {
-
- if (this.lonlat != null) {
- this.marker = new OpenLayers.Marker(this.lonlat, this.data.icon);
- }
- return this.marker;
- },
-
- /**
- * Method: destroyMarker
- * Destroys marker.
- * If user overrides the createMarker() function, s/he should be able
- * to also specify an alternative function for destroying it
- */
- destroyMarker: function() {
- this.marker.destroy();
- },
-
- /**
- * Method: createPopup
- * Creates a popup object created from the 'lonlat', 'popupSize',
- * and 'popupContentHTML' properties set in this.data. It uses
- * this.marker.icon as default anchor.
- *
- * If no 'lonlat' is set, returns null.
- * If no this.marker has been created, no anchor is sent.
- *
- * Note - the returned popup object is 'owned' by the feature, so you
- * cannot use the popup's destroy method to discard the popup.
- * Instead, you must use the feature's destroyPopup
- *
- * Note - this.popup is set to return value
- *
- * Parameters:
- * closeBox - {Boolean} create popup with closebox or not
- *
- * Returns:
- * {<OpenLayers.Popup>} Returns the created popup, which is also set
- * as 'popup' property of this feature. Will be of whatever type
- * specified by this feature's 'popupClass' property, but must be
- * of type <OpenLayers.Popup>.
- *
- */
- createPopup: function(closeBox) {
-
- if (this.lonlat != null) {
- if (!this.popup) {
- var anchor = (this.marker) ? this.marker.icon : null;
- var popupClass = this.popupClass ?
- this.popupClass : OpenLayers.Popup.Anchored;
- this.popup = new popupClass(this.id + "_popup",
- this.lonlat,
- this.data.popupSize,
- this.data.popupContentHTML,
- anchor,
- closeBox);
- }
- if (this.data.overflow != null) {
- this.popup.contentDiv.style.overflow = this.data.overflow;
- }
-
- this.popup.feature = this;
- }
- return this.popup;
- },
-
-
- /**
- * Method: destroyPopup
- * Destroys the popup created via createPopup.
- *
- * As with the marker, if user overrides the createPopup() function, s/he
- * should also be able to override the destruction
- */
- destroyPopup: function() {
- if (this.popup) {
- this.popup.feature = null;
- this.popup.destroy();
- this.popup = null;
- }
- },
-
- CLASS_NAME: "OpenLayers.Feature"
-});
-/* ======================================================================
- OpenLayers/Feature/Vector.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-// TRASH THIS
-OpenLayers.State = {
- /** states */
- UNKNOWN: 'Unknown',
- INSERT: 'Insert',
- UPDATE: 'Update',
- DELETE: 'Delete'
-};
-
-/**
- * @requires OpenLayers/Feature.js
- * @requires OpenLayers/Util.js
- */
-
-/**
- * Class: OpenLayers.Feature.Vector
- * Vector features use the OpenLayers.Geometry classes as geometry description.
- * They have an 'attributes' property, which is the data object, and a 'style'
- * property, the default values of which are defined in the
- * <OpenLayers.Feature.Vector.style> objects.
- *
- * Inherits from:
- * - <OpenLayers.Feature>
- */
-OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
-
- /**
- * Property: fid
- * {String}
- */
- fid: null,
-
- /**
- * APIProperty: geometry
- * {<OpenLayers.Geometry>}
- */
- geometry: null,
-
- /**
- * APIProperty: attributes
- * {Object} This object holds arbitrary, serializable properties that
- * describe the feature.
- */
- attributes: null,
-
- /**
- * Property: bounds
- * {<OpenLayers.Bounds>} The box bounding that feature's geometry, that
- * property can be set by an <OpenLayers.Format> object when
- * deserializing the feature, so in most cases it represents an
- * information set by the server.
- */
- bounds: null,
-
- /**
- * Property: state
- * {String}
- */
- state: null,
-
- /**
- * APIProperty: style
- * {Object}
- */
- style: null,
-
- /**
- * APIProperty: url
- * {String} If this property is set it will be taken into account by
- * {<OpenLayers.HTTP>} when upadting or deleting the feature.
- */
- url: null,
-
- /**
- * Property: renderIntent
- * {String} rendering intent currently being used
- */
- renderIntent: "default",
-
- /**
- * APIProperty: modified
- * {Object} An object with the originals of the geometry and attributes of
- * the feature, if they were changed. Currently this property is only read
- * by <OpenLayers.Format.WFST.v1>, and written by
- * <OpenLayers.Control.ModifyFeature>, which sets the geometry property.
- * Applications can set the originals of modified attributes in the
- * attributes property. Note that applications have to check if this
- * object and the attributes property is already created before using it.
- * After a change made with ModifyFeature, this object could look like
- *
- * (code)
- * {
- * geometry: >Object
- * }
- * (end)
- *
- * When an application has made changes to feature attributes, it could
- * have set the attributes to something like this:
- *
- * (code)
- * {
- * attributes: {
- * myAttribute: "original"
- * }
- * }
- * (end)
- *
- * Note that <OpenLayers.Format.WFST.v1> only checks for truthy values in
- * *modified.geometry* and the attribute names in *modified.attributes*,
- * but it is recommended to set the original values (and not just true) as
- * attribute value, so applications could use this information to undo
- * changes.
- */
- modified: null,
-
- /**
- * Constructor: OpenLayers.Feature.Vector
- * Create a vector feature.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The geometry that this feature
- * represents.
- * attributes - {Object} An optional object that will be mapped to the
- * <attributes> property.
- * style - {Object} An optional style object.
- */
- initialize: function(geometry, attributes, style) {
- OpenLayers.Feature.prototype.initialize.apply(this,
- [null, null, attributes]);
- this.lonlat = null;
- this.geometry = geometry ? geometry : null;
- this.state = null;
- this.attributes = {};
- if (attributes) {
- this.attributes = OpenLayers.Util.extend(this.attributes,
- attributes);
- }
- this.style = style ? style : null;
- },
-
- /**
- * Method: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- if (this.layer) {
- this.layer.removeFeatures(this);
- this.layer = null;
- }
-
- this.geometry = null;
- this.modified = null;
- OpenLayers.Feature.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clone
- * Create a clone of this vector feature. Does not set any non-standard
- * properties.
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} An exact clone of this vector feature.
- */
- clone: function () {
- return new OpenLayers.Feature.Vector(
- this.geometry ? this.geometry.clone() : null,
- this.attributes,
- this.style);
- },
-
- /**
- * Method: onScreen
- * Determine whether the feature is within the map viewport. This method
- * tests for an intersection between the geometry and the viewport
- * bounds. If a more effecient but less precise geometry bounds
- * intersection is desired, call the method with the boundsOnly
- * parameter true.
- *
- * Parameters:
- * boundsOnly - {Boolean} Only test whether a feature's bounds intersects
- * the viewport bounds. Default is false. If false, the feature's
- * geometry must intersect the viewport for onScreen to return true.
- *
- * Returns:
- * {Boolean} The feature is currently visible on screen (optionally
- * based on its bounds if boundsOnly is true).
- */
- onScreen:function(boundsOnly) {
- var onScreen = false;
- if(this.layer && this.layer.map) {
- var screenBounds = this.layer.map.getExtent();
- if(boundsOnly) {
- var featureBounds = this.geometry.getBounds();
- onScreen = screenBounds.intersectsBounds(featureBounds);
- } else {
- var screenPoly = screenBounds.toGeometry();
- onScreen = screenPoly.intersects(this.geometry);
- }
- }
- return onScreen;
- },
-
- /**
- * Method: getVisibility
- * Determine whether the feature is displayed or not. It may not displayed
- * because:
- * - its style display property is set to 'none',
- * - it doesn't belong to any layer,
- * - the styleMap creates a symbolizer with display property set to 'none'
- * for it,
- * - the layer which it belongs to is not visible.
- *
- * Returns:
- * {Boolean} The feature is currently displayed.
- */
- getVisibility: function() {
- return !(this.style && this.style.display == 'none' ||
- !this.layer ||
- this.layer && this.layer.styleMap &&
- this.layer.styleMap.createSymbolizer(this, this.renderIntent).display == 'none' ||
- this.layer && !this.layer.getVisibility());
- },
-
- /**
- * Method: createMarker
- * HACK - we need to decide if all vector features should be able to
- * create markers
- *
- * Returns:
- * {<OpenLayers.Marker>} For now just returns null
- */
- createMarker: function() {
- return null;
- },
-
- /**
- * Method: destroyMarker
- * HACK - we need to decide if all vector features should be able to
- * delete markers
- *
- * If user overrides the createMarker() function, s/he should be able
- * to also specify an alternative function for destroying it
- */
- destroyMarker: function() {
- // pass
- },
-
- /**
- * Method: createPopup
- * HACK - we need to decide if all vector features should be able to
- * create popups
- *
- * Returns:
- * {<OpenLayers.Popup>} For now just returns null
- */
- createPopup: function() {
- return null;
- },
-
- /**
- * Method: atPoint
- * Determins whether the feature intersects with the specified location.
- *
- * Parameters:
- * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
- * object with a 'lon' and 'lat' properties.
- * toleranceLon - {float} Optional tolerance in Geometric Coords
- * toleranceLat - {float} Optional tolerance in Geographic Coords
- *
- * Returns:
- * {Boolean} Whether or not the feature is at the specified location
- */
- atPoint: function(lonlat, toleranceLon, toleranceLat) {
- var atPoint = false;
- if(this.geometry) {
- atPoint = this.geometry.atPoint(lonlat, toleranceLon,
- toleranceLat);
- }
- return atPoint;
- },
-
- /**
- * Method: destroyPopup
- * HACK - we need to decide if all vector features should be able to
- * delete popups
- */
- destroyPopup: function() {
- // pass
- },
-
- /**
- * Method: move
- * Moves the feature and redraws it at its new location
- *
- * Parameters:
- * location - {<OpenLayers.LonLat> or <OpenLayers.Pixel>} the
- * location to which to move the feature.
- */
- move: function(location) {
-
- if(!this.layer || !this.geometry.move){
- //do nothing if no layer or immoveable geometry
- return undefined;
- }
-
- var pixel;
- if (location.CLASS_NAME == "OpenLayers.LonLat") {
- pixel = this.layer.getViewPortPxFromLonLat(location);
- } else {
- pixel = location;
- }
-
- var lastPixel = this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());
- var res = this.layer.map.getResolution();
- this.geometry.move(res * (pixel.x - lastPixel.x),
- res * (lastPixel.y - pixel.y));
- this.layer.drawFeature(this);
- return lastPixel;
- },
-
- /**
- * Method: toState
- * Sets the new state
- *
- * Parameters:
- * state - {String}
- */
- toState: function(state) {
- if (state == OpenLayers.State.UPDATE) {
- switch (this.state) {
- case OpenLayers.State.UNKNOWN:
- case OpenLayers.State.DELETE:
- this.state = state;
- break;
- case OpenLayers.State.UPDATE:
- case OpenLayers.State.INSERT:
- break;
- }
- } else if (state == OpenLayers.State.INSERT) {
- switch (this.state) {
- case OpenLayers.State.UNKNOWN:
- break;
- default:
- this.state = state;
- break;
- }
- } else if (state == OpenLayers.State.DELETE) {
- switch (this.state) {
- case OpenLayers.State.INSERT:
- // the feature should be destroyed
- break;
- case OpenLayers.State.DELETE:
- break;
- case OpenLayers.State.UNKNOWN:
- case OpenLayers.State.UPDATE:
- this.state = state;
- break;
- }
- } else if (state == OpenLayers.State.UNKNOWN) {
- this.state = state;
- }
- },
-
- CLASS_NAME: "OpenLayers.Feature.Vector"
-});
-
-
-/**
- * Constant: OpenLayers.Feature.Vector.style
- * OpenLayers features can have a number of style attributes. The 'default'
- * style will typically be used if no other style is specified. These
- * styles correspond for the most part, to the styling properties defined
- * by the SVG standard.
- * Information on fill properties: http://www.w3.org/TR/SVG/painting.html#FillProperties
- * Information on stroke properties: http://www.w3.org/TR/SVG/painting.html#StrokeProperties
- *
- * Symbolizer properties:
- * fill - {Boolean} Set to false if no fill is desired.
- * fillColor - {String} Hex fill color. Default is "#ee9900".
- * fillOpacity - {Number} Fill opacity (0-1). Default is 0.4
- * stroke - {Boolean} Set to false if no stroke is desired.
- * strokeColor - {String} Hex stroke color. Default is "#ee9900".
- * strokeOpacity - {Number} Stroke opacity (0-1). Default is 1.
- * strokeWidth - {Number} Pixel stroke width. Default is 1.
- * strokeLinecap - {String} Stroke cap type. Default is "round". [butt | round | square]
- * strokeDashstyle - {String} Stroke dash style. Default is "solid". [dot | dash | dashdot | longdash | longdashdot | solid]
- * graphic - {Boolean} Set to false if no graphic is desired.
- * pointRadius - {Number} Pixel point radius. Default is 6.
- * pointerEvents - {String} Default is "visiblePainted".
- * cursor - {String} Default is "".
- * externalGraphic - {String} Url to an external graphic that will be used for rendering points.
- * graphicWidth - {Number} Pixel width for sizing an external graphic.
- * graphicHeight - {Number} Pixel height for sizing an external graphic.
- * graphicOpacity - {Number} Opacity (0-1) for an external graphic.
- * graphicXOffset - {Number} Pixel offset along the positive x axis for displacing an external graphic.
- * graphicYOffset - {Number} Pixel offset along the positive y axis for displacing an external graphic.
- * rotation - {Number} For point symbolizers, this is the rotation of a graphic in the clockwise direction about its center point (or any point off center as specified by graphicXOffset and graphicYOffset).
- * graphicZIndex - {Number} The integer z-index value to use in rendering.
- * graphicName - {String} Named graphic to use when rendering points. Supported values include "circle" (default),
- * "square", "star", "x", "cross", "triangle".
- * graphicTitle - {String} Tooltip when hovering over a feature. *deprecated*, use title instead
- * title - {String} Tooltip when hovering over a feature. Not supported by the canvas renderer.
- * backgroundGraphic - {String} Url to a graphic to be used as the background under an externalGraphic.
- * backgroundGraphicZIndex - {Number} The integer z-index value to use in rendering the background graphic.
- * backgroundXOffset - {Number} The x offset (in pixels) for the background graphic.
- * backgroundYOffset - {Number} The y offset (in pixels) for the background graphic.
- * backgroundHeight - {Number} The height of the background graphic. If not provided, the graphicHeight will be used.
- * backgroundWidth - {Number} The width of the background width. If not provided, the graphicWidth will be used.
- * label - {String} The text for an optional label. For browsers that use the canvas renderer, this requires either
- * fillText or mozDrawText to be available.
- * labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
- * composed of two characters. The first character is for the horizontal alignment, the second for the vertical
- * alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
- * alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm".
- * labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.
- * labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.
- * labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
- * Default is false.
- * labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.
- * labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the SVG renderers.
- * labelOutlineOpacity - {Number} The opacity (0-1) of the label outline. Default is fontOpacity. Only supported by the canvas & SVG renderers.
- * fontColor - {String} The font color for the label, to be provided like CSS.
- * fontOpacity - {Number} Opacity (0-1) for the label
- * fontFamily - {String} The font family for the label, to be provided like in CSS.
- * fontSize - {String} The font size for the label, to be provided like in CSS.
- * fontStyle - {String} The font style for the label, to be provided like in CSS.
- * fontWeight - {String} The font weight for the label, to be provided like in CSS.
- * display - {String} Symbolizers will have no effect if display is set to "none". All other values have no effect.
- */
-OpenLayers.Feature.Vector.style = {
- 'default': {
- fillColor: "#ee9900",
- fillOpacity: 0.4,
- hoverFillColor: "white",
- hoverFillOpacity: 0.8,
- strokeColor: "#ee9900",
- strokeOpacity: 1,
- strokeWidth: 1,
- strokeLinecap: "round",
- strokeDashstyle: "solid",
- hoverStrokeColor: "red",
- hoverStrokeOpacity: 1,
- hoverStrokeWidth: 0.2,
- pointRadius: 6,
- hoverPointRadius: 1,
- hoverPointUnit: "%",
- pointerEvents: "visiblePainted",
- cursor: "inherit",
- fontColor: "#000000",
- labelAlign: "cm",
- labelOutlineColor: "white",
- labelOutlineWidth: 3
- },
- 'select': {
- fillColor: "blue",
- fillOpacity: 0.4,
- hoverFillColor: "white",
- hoverFillOpacity: 0.8,
- strokeColor: "blue",
- strokeOpacity: 1,
- strokeWidth: 2,
- strokeLinecap: "round",
- strokeDashstyle: "solid",
- hoverStrokeColor: "red",
- hoverStrokeOpacity: 1,
- hoverStrokeWidth: 0.2,
- pointRadius: 6,
- hoverPointRadius: 1,
- hoverPointUnit: "%",
- pointerEvents: "visiblePainted",
- cursor: "pointer",
- fontColor: "#000000",
- labelAlign: "cm",
- labelOutlineColor: "white",
- labelOutlineWidth: 3
-
- },
- 'temporary': {
- fillColor: "#66cccc",
- fillOpacity: 0.2,
- hoverFillColor: "white",
- hoverFillOpacity: 0.8,
- strokeColor: "#66cccc",
- strokeOpacity: 1,
- strokeLinecap: "round",
- strokeWidth: 2,
- strokeDashstyle: "solid",
- hoverStrokeColor: "red",
- hoverStrokeOpacity: 1,
- hoverStrokeWidth: 0.2,
- pointRadius: 6,
- hoverPointRadius: 1,
- hoverPointUnit: "%",
- pointerEvents: "visiblePainted",
- cursor: "inherit",
- fontColor: "#000000",
- labelAlign: "cm",
- labelOutlineColor: "white",
- labelOutlineWidth: 3
-
- },
- 'delete': {
- display: "none"
- }
-};
-/* ======================================================================
- OpenLayers/Style.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Style
- * This class represents a UserStyle obtained
- * from a SLD, containing styling rules.
- */
-OpenLayers.Style = OpenLayers.Class({
-
- /**
- * Property: id
- * {String} A unique id for this session.
- */
- id: null,
-
- /**
- * APIProperty: name
- * {String}
- */
- name: null,
-
- /**
- * Property: title
- * {String} Title of this style (set if included in SLD)
- */
- title: null,
-
- /**
- * Property: description
- * {String} Description of this style (set if abstract is included in SLD)
- */
- description: null,
-
- /**
- * APIProperty: layerName
- * {<String>} name of the layer that this style belongs to, usually
- * according to the NamedLayer attribute of an SLD document.
- */
- layerName: null,
-
- /**
- * APIProperty: isDefault
- * {Boolean}
- */
- isDefault: false,
-
- /**
- * Property: rules
- * {Array(<OpenLayers.Rule>)}
- */
- rules: null,
-
- /**
- * APIProperty: context
- * {Object} An optional object with properties that symbolizers' property
- * values should be evaluated against. If no context is specified,
- * feature.attributes will be used
- */
- context: null,
-
- /**
- * Property: defaultStyle
- * {Object} hash of style properties to use as default for merging
- * rule-based style symbolizers onto. If no rules are defined,
- * createSymbolizer will return this style. If <defaultsPerSymbolizer> is set to
- * true, the defaultStyle will only be taken into account if there are
- * rules defined.
- */
- defaultStyle: null,
-
- /**
- * Property: defaultsPerSymbolizer
- * {Boolean} If set to true, the <defaultStyle> will extend the symbolizer
- * of every rule. Properties of the <defaultStyle> will also be used to set
- * missing symbolizer properties if the symbolizer has stroke, fill or
- * graphic set to true. Default is false.
- */
- defaultsPerSymbolizer: false,
-
- /**
- * Property: propertyStyles
- * {Hash of Boolean} cache of style properties that need to be parsed for
- * propertyNames. Property names are keys, values won't be used.
- */
- propertyStyles: null,
-
-
- /**
- * Constructor: OpenLayers.Style
- * Creates a UserStyle.
- *
- * Parameters:
- * style - {Object} Optional hash of style properties that will be
- * used as default style for this style object. This style
- * applies if no rules are specified. Symbolizers defined in
- * rules will extend this default style.
- * options - {Object} An optional object with properties to set on the
- * style.
- *
- * Valid options:
- * rules - {Array(<OpenLayers.Rule>)} List of rules to be added to the
- * style.
- *
- * Returns:
- * {<OpenLayers.Style>}
- */
- initialize: function(style, options) {
-
- OpenLayers.Util.extend(this, options);
- this.rules = [];
- if(options && options.rules) {
- this.addRules(options.rules);
- }
-
- // use the default style from OpenLayers.Feature.Vector if no style
- // was given in the constructor
- this.setDefaultStyle(style ||
- OpenLayers.Feature.Vector.style["default"]);
-
- this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
- },
-
- /**
- * APIMethod: destroy
- * nullify references to prevent circular references and memory leaks
- */
- destroy: function() {
- for (var i=0, len=this.rules.length; i<len; i++) {
- this.rules[i].destroy();
- this.rules[i] = null;
- }
- this.rules = null;
- this.defaultStyle = null;
- },
-
- /**
- * Method: createSymbolizer
- * creates a style by applying all feature-dependent rules to the base
- * style.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature>} feature to evaluate rules for
- *
- * Returns:
- * {Object} symbolizer hash
- */
- createSymbolizer: function(feature) {
- var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(
- OpenLayers.Util.extend({}, this.defaultStyle), feature);
-
- var rules = this.rules;
-
- var rule, context;
- var elseRules = [];
- var appliedRules = false;
- for(var i=0, len=rules.length; i<len; i++) {
- rule = rules[i];
- // does the rule apply?
- var applies = rule.evaluate(feature);
-
- if(applies) {
- if(rule instanceof OpenLayers.Rule && rule.elseFilter) {
- elseRules.push(rule);
- } else {
- appliedRules = true;
- this.applySymbolizer(rule, style, feature);
- }
- }
- }
-
- // if no other rules apply, apply the rules with else filters
- if(appliedRules == false && elseRules.length > 0) {
- appliedRules = true;
- for(var i=0, len=elseRules.length; i<len; i++) {
- this.applySymbolizer(elseRules[i], style, feature);
- }
- }
-
- // don't display if there were rules but none applied
- if(rules.length > 0 && appliedRules == false) {
- style.display = "none";
- }
-
- if (style.label != null && typeof style.label !== "string") {
- style.label = String(style.label);
- }
-
- return style;
- },
-
- /**
- * Method: applySymbolizer
- *
- * Parameters:
- * rule - {<OpenLayers.Rule>}
- * style - {Object}
- * feature - {<OpenLayer.Feature.Vector>}
- *
- * Returns:
- * {Object} A style with new symbolizer applied.
- */
- applySymbolizer: function(rule, style, feature) {
- var symbolizerPrefix = feature.geometry ?
- this.getSymbolizerPrefix(feature.geometry) :
- OpenLayers.Style.SYMBOLIZER_PREFIXES[0];
-
- var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
-
- if(this.defaultsPerSymbolizer === true) {
- var defaults = this.defaultStyle;
- OpenLayers.Util.applyDefaults(symbolizer, {
- pointRadius: defaults.pointRadius
- });
- if(symbolizer.stroke === true || symbolizer.graphic === true) {
- OpenLayers.Util.applyDefaults(symbolizer, {
- strokeWidth: defaults.strokeWidth,
- strokeColor: defaults.strokeColor,
- strokeOpacity: defaults.strokeOpacity,
- strokeDashstyle: defaults.strokeDashstyle,
- strokeLinecap: defaults.strokeLinecap
- });
- }
- if(symbolizer.fill === true || symbolizer.graphic === true) {
- OpenLayers.Util.applyDefaults(symbolizer, {
- fillColor: defaults.fillColor,
- fillOpacity: defaults.fillOpacity
- });
- }
- if(symbolizer.graphic === true) {
- OpenLayers.Util.applyDefaults(symbolizer, {
- pointRadius: this.defaultStyle.pointRadius,
- externalGraphic: this.defaultStyle.externalGraphic,
- graphicName: this.defaultStyle.graphicName,
- graphicOpacity: this.defaultStyle.graphicOpacity,
- graphicWidth: this.defaultStyle.graphicWidth,
- graphicHeight: this.defaultStyle.graphicHeight,
- graphicXOffset: this.defaultStyle.graphicXOffset,
- graphicYOffset: this.defaultStyle.graphicYOffset
- });
- }
- }
-
- // merge the style with the current style
- return this.createLiterals(
- OpenLayers.Util.extend(style, symbolizer), feature);
- },
-
- /**
- * Method: createLiterals
- * creates literals for all style properties that have an entry in
- * <this.propertyStyles>.
- *
- * Parameters:
- * style - {Object} style to create literals for. Will be modified
- * inline.
- * feature - {Object}
- *
- * Returns:
- * {Object} the modified style
- */
- createLiterals: function(style, feature) {
- var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);
- OpenLayers.Util.extend(context, this.context);
-
- for (var i in this.propertyStyles) {
- style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);
- }
- return style;
- },
-
- /**
- * Method: findPropertyStyles
- * Looks into all rules for this style and the defaultStyle to collect
- * all the style hash property names containing ${...} strings that have
- * to be replaced using the createLiteral method before returning them.
- *
- * Returns:
- * {Object} hash of property names that need createLiteral parsing. The
- * name of the property is the key, and the value is true;
- */
- findPropertyStyles: function() {
- var propertyStyles = {};
-
- // check the default style
- var style = this.defaultStyle;
- this.addPropertyStyles(propertyStyles, style);
-
- // walk through all rules to check for properties in their symbolizer
- var rules = this.rules;
- var symbolizer, value;
- for (var i=0, len=rules.length; i<len; i++) {
- symbolizer = rules[i].symbolizer;
- for (var key in symbolizer) {
- value = symbolizer[key];
- if (typeof value == "object") {
- // symbolizer key is "Point", "Line" or "Polygon"
- this.addPropertyStyles(propertyStyles, value);
- } else {
- // symbolizer is a hash of style properties
- this.addPropertyStyles(propertyStyles, symbolizer);
- break;
- }
- }
- }
- return propertyStyles;
- },
-
- /**
- * Method: addPropertyStyles
- *
- * Parameters:
- * propertyStyles - {Object} hash to add new property styles to. Will be
- * modified inline
- * symbolizer - {Object} search this symbolizer for property styles
- *
- * Returns:
- * {Object} propertyStyles hash
- */
- addPropertyStyles: function(propertyStyles, symbolizer) {
- var property;
- for (var key in symbolizer) {
- property = symbolizer[key];
- if (typeof property == "string" &&
- property.match(/\$\{\w+\}/)) {
- propertyStyles[key] = true;
- }
- }
- return propertyStyles;
- },
-
- /**
- * APIMethod: addRules
- * Adds rules to this style.
- *
- * Parameters:
- * rules - {Array(<OpenLayers.Rule>)}
- */
- addRules: function(rules) {
- Array.prototype.push.apply(this.rules, rules);
- this.propertyStyles = this.findPropertyStyles();
- },
-
- /**
- * APIMethod: setDefaultStyle
- * Sets the default style for this style object.
- *
- * Parameters:
- * style - {Object} Hash of style properties
- */
- setDefaultStyle: function(style) {
- this.defaultStyle = style;
- this.propertyStyles = this.findPropertyStyles();
- },
-
- /**
- * Method: getSymbolizerPrefix
- * Returns the correct symbolizer prefix according to the
- * geometry type of the passed geometry
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {String} key of the according symbolizer
- */
- getSymbolizerPrefix: function(geometry) {
- var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
- for (var i=0, len=prefixes.length; i<len; i++) {
- if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {
- return prefixes[i];
- }
- }
- },
-
- /**
- * APIMethod: clone
- * Clones this style.
- *
- * Returns:
- * {<OpenLayers.Style>} Clone of this style.
- */
- clone: function() {
- var options = OpenLayers.Util.extend({}, this);
- // clone rules
- if(this.rules) {
- options.rules = [];
- for(var i=0, len=this.rules.length; i<len; ++i) {
- options.rules.push(this.rules[i].clone());
- }
- }
- // clone context
- options.context = this.context && OpenLayers.Util.extend({}, this.context);
- //clone default style
- var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);
- return new OpenLayers.Style(defaultStyle, options);
- },
-
- CLASS_NAME: "OpenLayers.Style"
-});
-
-
-/**
- * Function: createLiteral
- * converts a style value holding a combination of PropertyName and Literal
- * into a Literal, taking the property values from the passed features.
- *
- * Parameters:
- * value - {String} value to parse. If this string contains a construct like
- * "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
- * will be replaced by the value of the "bar" attribute of the passed
- * feature.
- * context - {Object} context to take attribute values from
- * feature - {<OpenLayers.Feature.Vector>} optional feature to pass to
- * <OpenLayers.String.format> for evaluating functions in the
- * context.
- * property - {String} optional, name of the property for which the literal is
- * being created for evaluating functions in the context.
- *
- * Returns:
- * {String} the parsed value. In the example of the value parameter above, the
- * result would be "foo valueOfBar", assuming that the passed feature has an
- * attribute named "bar" with the value "valueOfBar".
- */
-OpenLayers.Style.createLiteral = function(value, context, feature, property) {
- if (typeof value == "string" && value.indexOf("${") != -1) {
- value = OpenLayers.String.format(value, context, [feature, property]);
- value = (isNaN(value) || !value) ? value : parseFloat(value);
- }
- return value;
-};
-
-/**
- * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
- * {Array} prefixes of the sld symbolizers. These are the
- * same as the main geometry types
- */
-OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text',
- 'Raster'];
-/* ======================================================================
- OpenLayers/Filter.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/Style.js
- */
-
-/**
- * Class: OpenLayers.Filter
- * This class represents an OGC Filter.
- */
-OpenLayers.Filter = OpenLayers.Class({
-
- /**
- * Constructor: OpenLayers.Filter
- * This class represents a generic filter.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Returns:
- * {<OpenLayers.Filter>}
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * APIMethod: destroy
- * Remove reference to anything added.
- */
- destroy: function() {
- },
-
- /**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context. Instances or subclasses
- * are supposed to override this method.
- *
- * Parameters:
- * context - {Object} Context to use in evaluating the filter. If a vector
- * feature is provided, the feature.attributes will be used as context.
- *
- * Returns:
- * {Boolean} The filter applies.
- */
- evaluate: function(context) {
- return true;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter. Should be implemented by subclasses.
- *
- * Returns:
- * {<OpenLayers.Filter>} Clone of this filter.
- */
- clone: function() {
- return null;
- },
-
- /**
- * APIMethod: toString
- *
- * Returns:
- * {String} Include <OpenLayers.Format.CQL> in your build to get a CQL
- * representation of the filter returned. Otherwise "[Object object]"
- * will be returned.
- */
- toString: function() {
- var string;
- if (OpenLayers.Format && OpenLayers.Format.CQL) {
- string = OpenLayers.Format.CQL.prototype.write(this);
- } else {
- string = Object.prototype.toString.call(this);
- }
- return string;
- },
-
- CLASS_NAME: "OpenLayers.Filter"
-});
-/* ======================================================================
- OpenLayers/Filter/FeatureId.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.FeatureId
- * This class represents a ogc:FeatureId Filter, as being used for rule-based SLD
- * styling
- *
- * Inherits from:
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.FeatureId = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: fids
- * {Array(String)} Feature Ids to evaluate this rule against.
- * To be passed inside the params object.
- */
- fids: null,
-
- /**
- * Property: type
- * {String} Type to identify this filter.
- */
- type: "FID",
-
- /**
- * Constructor: OpenLayers.Filter.FeatureId
- * Creates an ogc:FeatureId rule.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * rule
- *
- * Returns:
- * {<OpenLayers.Filter.FeatureId>}
- */
- initialize: function(options) {
- this.fids = [];
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: evaluate
- * evaluates this rule for a specific feature
- *
- * Parameters:
- * feature - {<OpenLayers.Feature>} feature to apply the rule to.
- * For vector features, the check is run against the fid,
- * for plain features against the id.
- *
- * Returns:
- * {Boolean} true if the rule applies, false if it does not
- */
- evaluate: function(feature) {
- for (var i=0, len=this.fids.length; i<len; i++) {
- var fid = feature.fid || feature.id;
- if (fid == this.fids[i]) {
- return true;
- }
- }
- return false;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.FeatureId>} Clone of this filter.
- */
- clone: function() {
- var filter = new OpenLayers.Filter.FeatureId();
- OpenLayers.Util.extend(filter, this);
- filter.fids = this.fids.slice();
- return filter;
- },
-
- CLASS_NAME: "OpenLayers.Filter.FeatureId"
-});
-/* ======================================================================
- OpenLayers/Filter/Logical.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.Logical
- * This class represents ogc:And, ogc:Or and ogc:Not rules.
- *
- * Inherits from:
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Logical = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: filters
- * {Array(<OpenLayers.Filter>)} Child filters for this filter.
- */
- filters: null,
-
- /**
- * APIProperty: type
- * {String} type of logical operator. Available types are:
- * - OpenLayers.Filter.Logical.AND = "&&";
- * - OpenLayers.Filter.Logical.OR = "||";
- * - OpenLayers.Filter.Logical.NOT = "!";
- */
- type: null,
-
- /**
- * Constructor: OpenLayers.Filter.Logical
- * Creates a logical filter (And, Or, Not).
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Logical>}
- */
- initialize: function(options) {
- this.filters = [];
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: destroy
- * Remove reference to child filters.
- */
- destroy: function() {
- this.filters = null;
- OpenLayers.Filter.prototype.destroy.apply(this);
- },
-
- /**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context.
- *
- * Parameters:
- * context - {Object} Context to use in evaluating the filter. A vector
- * feature may also be provided to evaluate feature attributes in
- * comparison filters or geometries in spatial filters.
- *
- * Returns:
- * {Boolean} The filter applies.
- */
- evaluate: function(context) {
- var i, len;
- switch(this.type) {
- case OpenLayers.Filter.Logical.AND:
- for (i=0, len=this.filters.length; i<len; i++) {
- if (this.filters[i].evaluate(context) == false) {
- return false;
- }
- }
- return true;
-
- case OpenLayers.Filter.Logical.OR:
- for (i=0, len=this.filters.length; i<len; i++) {
- if (this.filters[i].evaluate(context) == true) {
- return true;
- }
- }
- return false;
-
- case OpenLayers.Filter.Logical.NOT:
- return (!this.filters[0].evaluate(context));
- }
- return undefined;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Logical>} Clone of this filter.
- */
- clone: function() {
- var filters = [];
- for(var i=0, len=this.filters.length; i<len; ++i) {
- filters.push(this.filters[i].clone());
- }
- return new OpenLayers.Filter.Logical({
- type: this.type,
- filters: filters
- });
- },
-
- CLASS_NAME: "OpenLayers.Filter.Logical"
-});
-
-
-OpenLayers.Filter.Logical.AND = "&&";
-OpenLayers.Filter.Logical.OR = "||";
-OpenLayers.Filter.Logical.NOT = "!";
-/* ======================================================================
- OpenLayers/Filter/Comparison.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.Comparison
- * This class represents a comparison filter.
- *
- * Inherits from:
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: type
- * {String} type: type of the comparison. This is one of
- * - OpenLayers.Filter.Comparison.EQUAL_TO = "==";
- * - OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
- * - OpenLayers.Filter.Comparison.LESS_THAN = "<";
- * - OpenLayers.Filter.Comparison.GREATER_THAN = ">";
- * - OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
- * - OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
- * - OpenLayers.Filter.Comparison.BETWEEN = "..";
- * - OpenLayers.Filter.Comparison.LIKE = "~";
- * - OpenLayers.Filter.Comparison.IS_NULL = "NULL";
- */
- type: null,
-
- /**
- * APIProperty: property
- * {String}
- * name of the context property to compare
- */
- property: null,
-
- /**
- * APIProperty: value
- * {Number} or {String}
- * comparison value for binary comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- value: null,
-
- /**
- * Property: matchCase
- * {Boolean} Force case sensitive searches for EQUAL_TO and NOT_EQUAL_TO
- * comparisons. The Filter Encoding 1.1 specification added a matchCase
- * attribute to ogc:PropertyIsEqualTo and ogc:PropertyIsNotEqualTo
- * elements. This property will be serialized with those elements only
- * if using the v1.1.0 filter format. However, when evaluating filters
- * here, the matchCase property will always be respected (for EQUAL_TO
- * and NOT_EQUAL_TO). Default is true.
- */
- matchCase: true,
-
- /**
- * APIProperty: lowerBoundary
- * {Number} or {String}
- * lower boundary for between comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- lowerBoundary: null,
-
- /**
- * APIProperty: upperBoundary
- * {Number} or {String}
- * upper boundary for between comparisons. In the case of a String, this
- * can be a combination of text and propertyNames in the form
- * "literal ${propertyName}"
- */
- upperBoundary: null,
-
- /**
- * Constructor: OpenLayers.Filter.Comparison
- * Creates a comparison rule.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * rule
- *
- * Returns:
- * {<OpenLayers.Filter.Comparison>}
- */
- initialize: function(options) {
- OpenLayers.Filter.prototype.initialize.apply(this, [options]);
- // since matchCase on PropertyIsLike is not schema compliant, we only
- // want to use this if explicitly asked for
- if (this.type === OpenLayers.Filter.Comparison.LIKE
- && options.matchCase === undefined) {
- this.matchCase = null;
- }
- },
-
- /**
- * APIMethod: evaluate
- * Evaluates this filter in a specific context.
- *
- * Parameters:
- * context - {Object} Context to use in evaluating the filter. If a vector
- * feature is provided, the feature.attributes will be used as context.
- *
- * Returns:
- * {Boolean} The filter applies.
- */
- evaluate: function(context) {
- if (context instanceof OpenLayers.Feature.Vector) {
- context = context.attributes;
- }
- var result = false;
- var got = context[this.property];
- var exp;
- switch(this.type) {
- case OpenLayers.Filter.Comparison.EQUAL_TO:
- exp = this.value;
- if(!this.matchCase &&
- typeof got == "string" && typeof exp == "string") {
- result = (got.toUpperCase() == exp.toUpperCase());
- } else {
- result = (got == exp);
- }
- break;
- case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:
- exp = this.value;
- if(!this.matchCase &&
- typeof got == "string" && typeof exp == "string") {
- result = (got.toUpperCase() != exp.toUpperCase());
- } else {
- result = (got != exp);
- }
- break;
- case OpenLayers.Filter.Comparison.LESS_THAN:
- result = got < this.value;
- break;
- case OpenLayers.Filter.Comparison.GREATER_THAN:
- result = got > this.value;
- break;
- case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:
- result = got <= this.value;
- break;
- case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:
- result = got >= this.value;
- break;
- case OpenLayers.Filter.Comparison.BETWEEN:
- result = (got >= this.lowerBoundary) &&
- (got <= this.upperBoundary);
- break;
- case OpenLayers.Filter.Comparison.LIKE:
- var regexp = new RegExp(this.value, "gi");
- result = regexp.test(got);
- break;
- case OpenLayers.Filter.Comparison.IS_NULL:
- result = (got === null);
- break;
- }
- return result;
- },
-
- /**
- * APIMethod: value2regex
- * Converts the value of this rule into a regular expression string,
- * according to the wildcard characters specified. This method has to
- * be called after instantiation of this class, if the value is not a
- * regular expression already.
- *
- * Parameters:
- * wildCard - {Char} wildcard character in the above value, default
- * is "*"
- * singleChar - {Char} single-character wildcard in the above value
- * default is "."
- * escapeChar - {Char} escape character in the above value, default is
- * "!"
- *
- * Returns:
- * {String} regular expression string
- */
- value2regex: function(wildCard, singleChar, escapeChar) {
- if (wildCard == ".") {
- throw new Error("'.' is an unsupported wildCard character for " +
- "OpenLayers.Filter.Comparison");
- }
-
-
- // set UMN MapServer defaults for unspecified parameters
- wildCard = wildCard ? wildCard : "*";
- singleChar = singleChar ? singleChar : ".";
- escapeChar = escapeChar ? escapeChar : "!";
-
- this.value = this.value.replace(
- new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
- this.value = this.value.replace(
- new RegExp("\\"+singleChar, "g"), ".");
- this.value = this.value.replace(
- new RegExp("\\"+wildCard, "g"), ".*");
- this.value = this.value.replace(
- new RegExp("\\\\.\\*", "g"), "\\"+wildCard);
- this.value = this.value.replace(
- new RegExp("\\\\\\.", "g"), "\\"+singleChar);
-
- return this.value;
- },
-
- /**
- * Method: regex2value
- * Convert the value of this rule from a regular expression string into an
- * ogc literal string using a wildCard of *, a singleChar of ., and an
- * escape of !. Leaves the <value> property unmodified.
- *
- * Returns:
- * {String} A string value.
- */
- regex2value: function() {
-
- var value = this.value;
-
- // replace ! with !!
- value = value.replace(/!/g, "!!");
-
- // replace \. with !. (watching out for \\.)
- value = value.replace(/(\\)?\\\./g, function($0, $1) {
- return $1 ? $0 : "!.";
- });
-
- // replace \* with #* (watching out for \\*)
- value = value.replace(/(\\)?\\\*/g, function($0, $1) {
- return $1 ? $0 : "!*";
- });
-
- // replace \\ with \
- value = value.replace(/\\\\/g, "\\");
-
- // convert .* to * (the sequence #.* is not allowed)
- value = value.replace(/\.\*/g, "*");
-
- return value;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Comparison>} Clone of this filter.
- */
- clone: function() {
- return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(), this);
- },
-
- CLASS_NAME: "OpenLayers.Filter.Comparison"
-});
-
-
-OpenLayers.Filter.Comparison.EQUAL_TO = "==";
-OpenLayers.Filter.Comparison.NOT_EQUAL_TO = "!=";
-OpenLayers.Filter.Comparison.LESS_THAN = "<";
-OpenLayers.Filter.Comparison.GREATER_THAN = ">";
-OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO = "<=";
-OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO = ">=";
-OpenLayers.Filter.Comparison.BETWEEN = "..";
-OpenLayers.Filter.Comparison.LIKE = "~";
-OpenLayers.Filter.Comparison.IS_NULL = "NULL";
-/* ======================================================================
- OpenLayers/Format/Filter.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/XML/VersionedOGC.js
- * @requires OpenLayers/Filter/FeatureId.js
- * @requires OpenLayers/Filter/Logical.js
- * @requires OpenLayers/Filter/Comparison.js
- */
-
-/**
- * Class: OpenLayers.Format.Filter
- * Read/Write ogc:Filter. Create a new instance with the <OpenLayers.Format.Filter>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML.VersionedOGC>
- */
-OpenLayers.Format.Filter = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, {
-
- /**
- * APIProperty: defaultVersion
- * {String} Version number to assume if none found. Default is "1.0.0".
- */
- defaultVersion: "1.0.0",
-
- /**
- * APIMethod: write
- * Write an ogc:Filter given a filter object.
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>} An filter.
- * options - {Object} Optional configuration object.
- *
- * Returns:
- * {Elment} An ogc:Filter element node.
- */
-
- /**
- * APIMethod: read
- * Read and Filter doc and return an object representing the Filter.
- *
- * Parameters:
- * data - {String | DOMElement} Data to read.
- *
- * Returns:
- * {<OpenLayers.Filter>} A filter object.
- */
-
- CLASS_NAME: "OpenLayers.Format.Filter"
-});
-/* ======================================================================
- OpenLayers/Format/WFST.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/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/Filter/Spatial.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.Spatial
- * This class represents a spatial filter.
- * Currently implemented: BBOX, DWithin and Intersects
- *
- * Inherits from:
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Spatial = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: type
- * {String} Type of spatial filter.
- *
- * The type should be one of:
- * - OpenLayers.Filter.Spatial.BBOX
- * - OpenLayers.Filter.Spatial.INTERSECTS
- * - OpenLayers.Filter.Spatial.DWITHIN
- * - OpenLayers.Filter.Spatial.WITHIN
- * - OpenLayers.Filter.Spatial.CONTAINS
- */
- type: null,
-
- /**
- * APIProperty: property
- * {String} Name of the context property to compare.
- */
- property: null,
-
- /**
- * APIProperty: value
- * {<OpenLayers.Bounds> || <OpenLayers.Geometry>} The bounds or geometry
- * to be used by the filter. Use bounds for BBOX filters and geometry
- * for INTERSECTS or DWITHIN filters.
- */
- value: null,
-
- /**
- * APIProperty: distance
- * {Number} The distance to use in a DWithin spatial filter.
- */
- distance: null,
-
- /**
- * APIProperty: distanceUnits
- * {String} The units to use for the distance, e.g. 'm'.
- */
- distanceUnits: null,
-
- /**
- * Constructor: OpenLayers.Filter.Spatial
- * Creates a spatial filter.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Spatial>}
- */
-
- /**
- * Method: evaluate
- * Evaluates this filter for a specific feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} feature to apply the filter to.
- *
- * Returns:
- * {Boolean} The feature meets filter criteria.
- */
- evaluate: function(feature) {
- var intersect = false;
- switch(this.type) {
- case OpenLayers.Filter.Spatial.BBOX:
- case OpenLayers.Filter.Spatial.INTERSECTS:
- if(feature.geometry) {
- var geom = this.value;
- if(this.value.CLASS_NAME == "OpenLayers.Bounds") {
- geom = this.value.toGeometry();
- }
- if(feature.geometry.intersects(geom)) {
- intersect = true;
- }
- }
- break;
- default:
- throw new Error('evaluate is not implemented for this filter type.');
- }
- return intersect;
- },
-
- /**
- * APIMethod: clone
- * Clones this filter.
- *
- * Returns:
- * {<OpenLayers.Filter.Spatial>} Clone of this filter.
- */
- clone: function() {
- var options = OpenLayers.Util.applyDefaults({
- value: this.value && this.value.clone && this.value.clone()
- }, this);
- return new OpenLayers.Filter.Spatial(options);
- },
- CLASS_NAME: "OpenLayers.Filter.Spatial"
-});
-
-OpenLayers.Filter.Spatial.BBOX = "BBOX";
-OpenLayers.Filter.Spatial.INTERSECTS = "INTERSECTS";
-OpenLayers.Filter.Spatial.DWITHIN = "DWITHIN";
-OpenLayers.Filter.Spatial.WITHIN = "WITHIN";
-OpenLayers.Filter.Spatial.CONTAINS = "CONTAINS";
-/* ======================================================================
- OpenLayers/Format/WFST/v1.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Format/WFST.js
- * @requires OpenLayers/Filter/Spatial.js
- * @requires OpenLayers/Filter/FeatureId.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/Geometry/Polygon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Geometry/LinearRing.js
- */
-
-/**
- * Class: OpenLayers.Geometry.Polygon
- * Polygon is a collection of Geometry.LinearRings.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Collection>
- * - <OpenLayers.Geometry>
- */
-OpenLayers.Geometry.Polygon = OpenLayers.Class(
- OpenLayers.Geometry.Collection, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.LinearRing"],
-
- /**
- * Constructor: OpenLayers.Geometry.Polygon
- * Constructor for a Polygon geometry.
- * The first ring (this.component[0])is the outer bounds of the polygon and
- * all subsequent rings (this.component[1-n]) are internal holes.
- *
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.LinearRing>)}
- */
-
- /**
- * APIMethod: getArea
- * Calculated by subtracting the areas of the internal holes from the
- * area of the outer hole.
- *
- * Returns:
- * {float} The area of the geometry
- */
- getArea: function() {
- var area = 0.0;
- if ( this.components && (this.components.length > 0)) {
- area += Math.abs(this.components[0].getArea());
- for (var i=1, len=this.components.length; i<len; i++) {
- area -= Math.abs(this.components[i].getArea());
- }
- }
- return area;
- },
-
- /**
- * APIMethod: getGeodesicArea
- * Calculate the approximate area of the polygon were it projected onto
- * the earth.
- *
- * Parameters:
- * projection - {<OpenLayers.Projection>} The spatial reference system
- * for the geometry coordinates. If not provided, Geographic/WGS84 is
- * assumed.
- *
- * Reference:
- * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
- * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
- * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
- *
- * Returns:
- * {float} The approximate geodesic area of the polygon in square meters.
- */
- getGeodesicArea: function(projection) {
- var area = 0.0;
- if(this.components && (this.components.length > 0)) {
- area += Math.abs(this.components[0].getGeodesicArea(projection));
- for(var i=1, len=this.components.length; i<len; i++) {
- area -= Math.abs(this.components[i].getGeodesicArea(projection));
- }
- }
- return area;
- },
-
- /**
- * Method: containsPoint
- * Test if a point is inside a polygon. Points on a polygon edge are
- * considered inside.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {Boolean | Number} The point is inside the polygon. Returns 1 if the
- * point is on an edge. Returns boolean otherwise.
- */
- containsPoint: function(point) {
- var numRings = this.components.length;
- var contained = false;
- if(numRings > 0) {
- // check exterior ring - 1 means on edge, boolean otherwise
- contained = this.components[0].containsPoint(point);
- if(contained !== 1) {
- if(contained && numRings > 1) {
- // check interior rings
- var hole;
- for(var i=1; i<numRings; ++i) {
- hole = this.components[i].containsPoint(point);
- if(hole) {
- if(hole === 1) {
- // on edge
- contained = 1;
- } else {
- // in hole
- contained = false;
- }
- break;
- }
- }
- }
- }
- }
- return contained;
- },
-
- /**
- * APIMethod: intersects
- * Determine if the input geometry intersects this one.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} Any type of geometry.
- *
- * Returns:
- * {Boolean} The input geometry intersects this one.
- */
- intersects: function(geometry) {
- var intersect = false;
- var i, len;
- if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
- intersect = this.containsPoint(geometry);
- } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" ||
- geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
- // check if rings/linestrings intersect
- for(i=0, len=this.components.length; i<len; ++i) {
- intersect = geometry.intersects(this.components[i]);
- if(intersect) {
- break;
- }
- }
- if(!intersect) {
- // check if this poly contains points of the ring/linestring
- for(i=0, len=geometry.components.length; i<len; ++i) {
- intersect = this.containsPoint(geometry.components[i]);
- if(intersect) {
- break;
- }
- }
- }
- } else {
- for(i=0, len=geometry.components.length; i<len; ++ i) {
- intersect = this.intersects(geometry.components[i]);
- if(intersect) {
- break;
- }
- }
- }
- // check case where this poly is wholly contained by another
- if(!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
- // exterior ring points will be contained in the other geometry
- var ring = this.components[0];
- for(i=0, len=ring.components.length; i<len; ++i) {
- intersect = geometry.containsPoint(ring.components[i]);
- if(intersect) {
- break;
- }
- }
- }
- return intersect;
- },
-
- /**
- * APIMethod: distanceTo
- * Calculate the closest distance between two geometries (on the x-y plane).
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>} The target geometry.
- * options - {Object} Optional properties for configuring the distance
- * calculation.
- *
- * Valid options:
- * details - {Boolean} Return details from the distance calculation.
- * Default is false.
- * edge - {Boolean} Calculate the distance from this geometry to the
- * nearest edge of the target geometry. Default is true. If true,
- * calling distanceTo from a geometry that is wholly contained within
- * the target will result in a non-zero distance. If false, whenever
- * geometries intersect, calling distanceTo will return 0. If false,
- * details cannot be returned.
- *
- * Returns:
- * {Number | Object} The distance between this geometry and the target.
- * If details is true, the return will be an object with distance,
- * x0, y0, x1, and y1 properties. The x0 and y0 properties represent
- * the coordinates of the closest point on this geometry. The x1 and y1
- * properties represent the coordinates of the closest point on the
- * target geometry.
- */
- distanceTo: function(geometry, options) {
- var edge = !(options && options.edge === false);
- var result;
- // this is the case where we might not be looking for distance to edge
- if(!edge && this.intersects(geometry)) {
- result = 0;
- } else {
- result = OpenLayers.Geometry.Collection.prototype.distanceTo.apply(
- this, [geometry, options]
- );
- }
- return result;
- },
-
- CLASS_NAME: "OpenLayers.Geometry.Polygon"
-});
-
-/**
- * APIMethod: createRegularPolygon
- * Create a regular polygon around a radius. Useful for creating circles
- * and the like.
- *
- * Parameters:
- * origin - {<OpenLayers.Geometry.Point>} center of polygon.
- * radius - {Float} distance to vertex, in map units.
- * sides - {Integer} Number of sides. 20 approximates a circle.
- * rotation - {Float} original angle of rotation, in degrees.
- */
-OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {
- var angle = Math.PI * ((1/sides) - (1/2));
- if(rotation) {
- angle += (rotation / 180) * Math.PI;
- }
- var rotatedAngle, x, y;
- var points = [];
- for(var i=0; i<sides; ++i) {
- rotatedAngle = angle + (i * 2 * Math.PI / sides);
- x = origin.x + (radius * Math.cos(rotatedAngle));
- y = origin.y + (radius * Math.sin(rotatedAngle));
- points.push(new OpenLayers.Geometry.Point(x, y));
- }
- var ring = new OpenLayers.Geometry.LinearRing(points);
- return new OpenLayers.Geometry.Polygon([ring]);
-};
-/* ======================================================================
- OpenLayers/Geometry/MultiPolygon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Geometry/Polygon.js
- */
-
-/**
- * Class: OpenLayers.Geometry.MultiPolygon
- * MultiPolygon is a geometry with multiple <OpenLayers.Geometry.Polygon>
- * components. Create a new instance with the <OpenLayers.Geometry.MultiPolygon>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Geometry.Collection>
- */
-OpenLayers.Geometry.MultiPolygon = OpenLayers.Class(
- OpenLayers.Geometry.Collection, {
-
- /**
- * Property: componentTypes
- * {Array(String)} An array of class names representing the types of
- * components that the collection can include. A null value means the
- * component types are not restricted.
- */
- componentTypes: ["OpenLayers.Geometry.Polygon"],
-
- /**
- * Constructor: OpenLayers.Geometry.MultiPolygon
- * Create a new MultiPolygon geometry
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.Polygon>)} An array of polygons
- * used to generate the MultiPolygon
- *
- */
-
- CLASS_NAME: "OpenLayers.Geometry.MultiPolygon"
-});
-/* ======================================================================
- OpenLayers/Format/GML.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/MultiPoint.js
- * @requires OpenLayers/Geometry/LineString.js
- * @requires OpenLayers/Geometry/MultiLineString.js
- * @requires OpenLayers/Geometry/Polygon.js
- * @requires OpenLayers/Geometry/MultiPolygon.js
- */
-
-/**
- * Class: OpenLayers.Format.GML
- * Read/Write GML. Create a new instance with the <OpenLayers.Format.GML>
- * constructor. Supports the GML simple features profile.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * APIProperty: featureNS
- * {String} Namespace used for feature attributes. Default is
- * "http://mapserver.gis.umn.edu/mapserver".
- */
- featureNS: "http://mapserver.gis.umn.edu/mapserver",
-
- /**
- * APIProperty: featurePrefix
- * {String} Namespace alias (or prefix) for feature nodes. Default is
- * "feature".
- */
- featurePrefix: "feature",
-
- /**
- * APIProperty: featureName
- * {String} Element name for features. Default is "featureMember".
- */
- featureName: "featureMember",
-
- /**
- * APIProperty: layerName
- * {String} Name of data layer. Default is "features".
- */
- layerName: "features",
-
- /**
- * APIProperty: geometryName
- * {String} Name of geometry element. Defaults to "geometry".
- */
- geometryName: "geometry",
-
- /**
- * APIProperty: collectionName
- * {String} Name of featureCollection element.
- */
- collectionName: "FeatureCollection",
-
- /**
- * APIProperty: gmlns
- * {String} GML Namespace.
- */
- gmlns: "http://www.opengis.net/gml",
-
- /**
- * APIProperty: extractAttributes
- * {Boolean} Extract attributes from GML.
- */
- 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,
-
- /**
- * Constructor: OpenLayers.Format.GML
- * Create a new parser for GML.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(options) {
- // compile regular expressions once instead of every time they are used
- this.regExes = {
- trimSpace: (/^\s*|\s*$/g),
- removeSpace: (/\s*/g),
- splitSpace: (/\s+/),
- trimComma: (/\s*,\s*/g)
- };
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: read
- * Read data from a string, and return a list of features.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} An array of features.
- */
- read: function(data) {
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
- var featureNodes = this.getElementsByTagNameNS(data.documentElement,
- this.gmlns,
- this.featureName);
- var features = [];
- for(var i=0; i<featureNodes.length; i++) {
- var feature = this.parseFeature(featureNodes[i]);
- if(feature) {
- features.push(feature);
- }
- }
- return features;
- },
-
- /**
- * Method: parseFeature
- * This function is the core of the GML parsing code in OpenLayers.
- * It creates the geometries that are then attached to the returned
- * feature, and calls parseAttributes() to get attribute data out.
- *
- * Parameters:
- * node - {DOMElement} A GML feature node.
- */
- parseFeature: function(node) {
- // only accept one geometry per feature - look for highest "order"
- var order = ["MultiPolygon", "Polygon",
- "MultiLineString", "LineString",
- "MultiPoint", "Point", "Envelope"];
- // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope,
- // this code creates a geometry derived from the Envelope. This is not correct.
- var type, nodeList, geometry, parser;
- for(var i=0; i<order.length; ++i) {
- type = order[i];
- nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
- if(nodeList.length > 0) {
- // only deal with first geometry of this type
- parser = this.parseGeometry[type.toLowerCase()];
- if(parser) {
- geometry = parser.apply(this, [nodeList[0]]);
- if (this.internalProjection && this.externalProjection) {
- geometry.transform(this.externalProjection,
- this.internalProjection);
- }
- } else {
- throw new TypeError("Unsupported geometry type: " + type);
- }
- // stop looking for different geometry types
- break;
- }
- }
-
- var bounds;
- var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box");
- for(i=0; i<boxNodes.length; ++i) {
- var boxNode = boxNodes[i];
- var box = this.parseGeometry["box"].apply(this, [boxNode]);
- var parentNode = boxNode.parentNode;
- var parentName = parentNode.localName ||
- parentNode.nodeName.split(":").pop();
- if(parentName === "boundedBy") {
- bounds = box;
- } else {
- geometry = box.toGeometry();
- }
- }
-
- // construct feature (optionally with attributes)
- var attributes;
- if(this.extractAttributes) {
- attributes = this.parseAttributes(node);
- }
- var feature = new OpenLayers.Feature.Vector(geometry, attributes);
- feature.bounds = bounds;
-
- feature.gml = {
- featureType: node.firstChild.nodeName.split(":")[1],
- featureNS: node.firstChild.namespaceURI,
- featureNSPrefix: node.firstChild.prefix
- };
-
- // assign fid - this can come from a "fid" or "id" attribute
- var childNode = node.firstChild;
- var fid;
- while(childNode) {
- if(childNode.nodeType == 1) {
- fid = childNode.getAttribute("fid") ||
- childNode.getAttribute("id");
- if(fid) {
- break;
- }
- }
- childNode = childNode.nextSibling;
- }
- feature.fid = fid;
- return feature;
- },
-
- /**
- * Property: parseGeometry
- * Properties of this object are the functions that parse geometries based
- * on their type.
- */
- parseGeometry: {
-
- /**
- * Method: parseGeometry.point
- * Given a GML node representing a point geometry, create an OpenLayers
- * point geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} A point geometry.
- */
- point: function(node) {
- /**
- * Three coordinate variations to consider:
- * 1) <gml:pos>x y z</gml:pos>
- * 2) <gml:coordinates>x, y, z</gml:coordinates>
- * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
- */
- var nodeList, coordString;
- var coords = [];
-
- // look for <gml:pos>
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos");
- if(nodeList.length > 0) {
- coordString = nodeList[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.trimSpace, "");
- coords = coordString.split(this.regExes.splitSpace);
- }
-
- // look for <gml:coordinates>
- if(coords.length == 0) {
- nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "coordinates");
- if(nodeList.length > 0) {
- coordString = nodeList[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.removeSpace,
- "");
- coords = coordString.split(",");
- }
- }
-
- // look for <gml:coord>
- if(coords.length == 0) {
- nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "coord");
- if(nodeList.length > 0) {
- var xList = this.getElementsByTagNameNS(nodeList[0],
- this.gmlns, "X");
- var yList = this.getElementsByTagNameNS(nodeList[0],
- this.gmlns, "Y");
- if(xList.length > 0 && yList.length > 0) {
- coords = [xList[0].firstChild.nodeValue,
- yList[0].firstChild.nodeValue];
- }
- }
- }
-
- // preserve third dimension
- if(coords.length == 2) {
- coords[2] = null;
- }
-
- if (this.xy) {
- return new OpenLayers.Geometry.Point(coords[0], coords[1],
- coords[2]);
- }
- else{
- return new OpenLayers.Geometry.Point(coords[1], coords[0],
- coords[2]);
- }
- },
-
- /**
- * Method: parseGeometry.multipoint
- * Given a GML node representing a multipoint geometry, create an
- * OpenLayers multipoint geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
- */
- multipoint: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "Point");
- var components = [];
- if(nodeList.length > 0) {
- var point;
- for(var i=0; i<nodeList.length; ++i) {
- point = this.parseGeometry.point.apply(this, [nodeList[i]]);
- if(point) {
- components.push(point);
- }
- }
- }
- return new OpenLayers.Geometry.MultiPoint(components);
- },
-
- /**
- * Method: parseGeometry.linestring
- * Given a GML node representing a linestring geometry, create an
- * OpenLayers linestring geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.LineString>} A linestring geometry.
- */
- linestring: function(node, ring) {
- /**
- * Two coordinate variations to consider:
- * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
- * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
- */
- var nodeList, coordString;
- var coords = [];
- var points = [];
-
- // look for <gml:posList>
- nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList");
- if(nodeList.length > 0) {
- coordString = this.getChildValue(nodeList[0]);
- coordString = coordString.replace(this.regExes.trimSpace, "");
- coords = coordString.split(this.regExes.splitSpace);
- var dim = parseInt(nodeList[0].getAttribute("dimension"));
- var j, x, y, z;
- for(var i=0; i<coords.length/dim; ++i) {
- j = i * dim;
- x = coords[j];
- y = coords[j+1];
- z = (dim == 2) ? null : coords[j+2];
- if (this.xy) {
- points.push(new OpenLayers.Geometry.Point(x, y, z));
- } else {
- points.push(new OpenLayers.Geometry.Point(y, x, z));
- }
- }
- }
-
- // look for <gml:coordinates>
- if(coords.length == 0) {
- nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "coordinates");
- if(nodeList.length > 0) {
- coordString = this.getChildValue(nodeList[0]);
- coordString = coordString.replace(this.regExes.trimSpace,
- "");
- coordString = coordString.replace(this.regExes.trimComma,
- ",");
- var pointList = coordString.split(this.regExes.splitSpace);
- for(var i=0; i<pointList.length; ++i) {
- coords = pointList[i].split(",");
- if(coords.length == 2) {
- coords[2] = null;
- }
- if (this.xy) {
- points.push(new OpenLayers.Geometry.Point(coords[0],
- coords[1],
- coords[2]));
- } else {
- points.push(new OpenLayers.Geometry.Point(coords[1],
- coords[0],
- coords[2]));
- }
- }
- }
- }
-
- var line = null;
- if(points.length != 0) {
- if(ring) {
- line = new OpenLayers.Geometry.LinearRing(points);
- } else {
- line = new OpenLayers.Geometry.LineString(points);
- }
- }
- return line;
- },
-
- /**
- * Method: parseGeometry.multilinestring
- * Given a GML node representing a multilinestring geometry, create an
- * OpenLayers multilinestring geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.MultiLineString>} A multilinestring geometry.
- */
- multilinestring: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "LineString");
- var components = [];
- if(nodeList.length > 0) {
- var line;
- for(var i=0; i<nodeList.length; ++i) {
- line = this.parseGeometry.linestring.apply(this,
- [nodeList[i]]);
- if(line) {
- components.push(line);
- }
- }
- }
- return new OpenLayers.Geometry.MultiLineString(components);
- },
-
- /**
- * Method: parseGeometry.polygon
- * Given a GML node representing a polygon geometry, create an
- * OpenLayers polygon geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
- */
- polygon: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "LinearRing");
- var components = [];
- if(nodeList.length > 0) {
- // this assumes exterior ring first, inner rings after
- var ring;
- for(var i=0; i<nodeList.length; ++i) {
- ring = this.parseGeometry.linestring.apply(this,
- [nodeList[i], true]);
- if(ring) {
- components.push(ring);
- }
- }
- }
- return new OpenLayers.Geometry.Polygon(components);
- },
-
- /**
- * Method: parseGeometry.multipolygon
- * Given a GML node representing a multipolygon geometry, create an
- * OpenLayers multipolygon geometry.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry.
- */
- multipolygon: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "Polygon");
- var components = [];
- if(nodeList.length > 0) {
- var polygon;
- for(var i=0; i<nodeList.length; ++i) {
- polygon = this.parseGeometry.polygon.apply(this,
- [nodeList[i]]);
- if(polygon) {
- components.push(polygon);
- }
- }
- }
- return new OpenLayers.Geometry.MultiPolygon(components);
- },
-
- envelope: function(node) {
- var components = [];
- var coordString;
- var envelope;
-
- var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner");
- if (lpoint.length > 0) {
- var coords = [];
-
- if(lpoint.length > 0) {
- coordString = lpoint[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.trimSpace, "");
- coords = coordString.split(this.regExes.splitSpace);
- }
-
- if(coords.length == 2) {
- coords[2] = null;
- }
- if (this.xy) {
- var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
- } else {
- var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
- }
- }
-
- var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner");
- if (upoint.length > 0) {
- var coords = [];
-
- if(upoint.length > 0) {
- coordString = upoint[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.trimSpace, "");
- coords = coordString.split(this.regExes.splitSpace);
- }
-
- if(coords.length == 2) {
- coords[2] = null;
- }
- if (this.xy) {
- var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
- } else {
- var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
- }
- }
-
- if (lowerPoint && upperPoint) {
- components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
- components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y));
- components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y));
- components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y));
- components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
-
- var ring = new OpenLayers.Geometry.LinearRing(components);
- envelope = new OpenLayers.Geometry.Polygon([ring]);
- }
- return envelope;
- },
-
- /**
- * Method: parseGeometry.box
- * Given a GML node representing a box geometry, create an
- * OpenLayers.Bounds.
- *
- * Parameters:
- * node - {DOMElement} A GML node.
- *
- * Returns:
- * {<OpenLayers.Bounds>} A bounds representing the box.
- */
- box: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
- "coordinates");
- var coordString;
- var coords, beginPoint = null, endPoint = null;
- if (nodeList.length > 0) {
- coordString = nodeList[0].firstChild.nodeValue;
- coords = coordString.split(" ");
- if (coords.length == 2) {
- beginPoint = coords[0].split(",");
- endPoint = coords[1].split(",");
- }
- }
- if (beginPoint !== null && endPoint !== null) {
- return new OpenLayers.Bounds(parseFloat(beginPoint[0]),
- parseFloat(beginPoint[1]),
- parseFloat(endPoint[0]),
- parseFloat(endPoint[1]) );
- }
- }
-
- },
-
- /**
- * Method: parseAttributes
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Object} An attributes object.
- */
- parseAttributes: function(node) {
- var attributes = {};
- // assume attributes are children of the first type 1 child
- var childNode = node.firstChild;
- var children, i, child, grandchildren, grandchild, name, value;
- while(childNode) {
- if(childNode.nodeType == 1) {
- // attributes are type 1 children with one type 3 child
- children = childNode.childNodes;
- for(i=0; i<children.length; ++i) {
- child = children[i];
- if(child.nodeType == 1) {
- grandchildren = child.childNodes;
- if(grandchildren.length == 1) {
- grandchild = grandchildren[0];
- if(grandchild.nodeType == 3 ||
- grandchild.nodeType == 4) {
- name = (child.prefix) ?
- child.nodeName.split(":")[1] :
- child.nodeName;
- value = grandchild.nodeValue.replace(
- this.regExes.trimSpace, "");
- attributes[name] = value;
- }
- } else {
- // If child has no childNodes (grandchildren),
- // set an attribute with null value.
- // e.g. <prefix:fieldname/> becomes
- // {fieldname: null}
- attributes[child.nodeName.split(":").pop()] = null;
- }
- }
- }
- break;
- }
- childNode = childNode.nextSibling;
- }
- return attributes;
- },
-
- /**
- * APIMethod: write
- * Generate a GML document string given a list of features.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} List of features to
- * serialize into a string.
- *
- * Returns:
- * {String} A string representing the GML document.
- */
- write: function(features) {
- if(!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- var gml = this.createElementNS("http://www.opengis.net/wfs",
- "wfs:" + this.collectionName);
- for(var i=0; i<features.length; i++) {
- gml.appendChild(this.createFeatureXML(features[i]));
- }
- return OpenLayers.Format.XML.prototype.write.apply(this, [gml]);
- },
-
- /**
- * Method: createFeatureXML
- * Accept an OpenLayers.Feature.Vector, and build a GML node for it.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML.
- *
- * Returns:
- * {DOMElement} A node reprensting the feature in GML.
- */
- createFeatureXML: function(feature) {
- var geometry = feature.geometry;
- var geometryNode = this.buildGeometryNode(geometry);
- var geomContainer = this.createElementNS(this.featureNS,
- this.featurePrefix + ":" +
- this.geometryName);
- geomContainer.appendChild(geometryNode);
- var featureNode = this.createElementNS(this.gmlns,
- "gml:" + this.featureName);
- var featureContainer = this.createElementNS(this.featureNS,
- this.featurePrefix + ":" +
- this.layerName);
- var fid = feature.fid || feature.id;
- featureContainer.setAttribute("fid", fid);
- featureContainer.appendChild(geomContainer);
- for(var attr in feature.attributes) {
- var attrText = this.createTextNode(feature.attributes[attr]);
- var nodename = attr.substring(attr.lastIndexOf(":") + 1);
- var attrContainer = this.createElementNS(this.featureNS,
- this.featurePrefix + ":" +
- nodename);
- attrContainer.appendChild(attrText);
- featureContainer.appendChild(attrContainer);
- }
- featureNode.appendChild(featureContainer);
- return featureNode;
- },
-
- /**
- * APIMethod: buildGeometryNode
- */
- buildGeometryNode: function(geometry) {
- if (this.externalProjection && this.internalProjection) {
- geometry = geometry.clone();
- geometry.transform(this.internalProjection,
- this.externalProjection);
- }
- var className = geometry.CLASS_NAME;
- var type = className.substring(className.lastIndexOf(".") + 1);
- var builder = this.buildGeometry[type.toLowerCase()];
- return builder.apply(this, [geometry]);
- },
-
- /**
- * Property: buildGeometry
- * Object containing methods to do the actual geometry node building
- * based on geometry type.
- */
- buildGeometry: {
- // TBD retrieve the srs from layer
- // srsName is non-standard, so not including it until it's right.
- // gml.setAttribute("srsName",
- // "http://www.opengis.net/gml/srs/epsg.xml#4326");
-
- /**
- * Method: buildGeometry.point
- * Given an OpenLayers point geometry, create a GML point.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
- *
- * Returns:
- * {DOMElement} A GML point node.
- */
- point: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:Point");
- gml.appendChild(this.buildCoordinatesNode(geometry));
- return gml;
- },
-
- /**
- * Method: buildGeometry.multipoint
- * Given an OpenLayers multipoint geometry, create a GML multipoint.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
- *
- * Returns:
- * {DOMElement} A GML multipoint node.
- */
- multipoint: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:MultiPoint");
- var points = geometry.components;
- var pointMember, pointGeom;
- for(var i=0; i<points.length; i++) {
- pointMember = this.createElementNS(this.gmlns,
- "gml:pointMember");
- pointGeom = this.buildGeometry.point.apply(this,
- [points[i]]);
- pointMember.appendChild(pointGeom);
- gml.appendChild(pointMember);
- }
- return gml;
- },
-
- /**
- * Method: buildGeometry.linestring
- * Given an OpenLayers linestring geometry, create a GML linestring.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
- *
- * Returns:
- * {DOMElement} A GML linestring node.
- */
- linestring: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:LineString");
- gml.appendChild(this.buildCoordinatesNode(geometry));
- return gml;
- },
-
- /**
- * Method: buildGeometry.multilinestring
- * Given an OpenLayers multilinestring geometry, create a GML
- * multilinestring.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring
- * geometry.
- *
- * Returns:
- * {DOMElement} A GML multilinestring node.
- */
- multilinestring: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:MultiLineString");
- var lines = geometry.components;
- var lineMember, lineGeom;
- for(var i=0; i<lines.length; ++i) {
- lineMember = this.createElementNS(this.gmlns,
- "gml:lineStringMember");
- lineGeom = this.buildGeometry.linestring.apply(this,
- [lines[i]]);
- lineMember.appendChild(lineGeom);
- gml.appendChild(lineMember);
- }
- return gml;
- },
-
- /**
- * Method: buildGeometry.linearring
- * Given an OpenLayers linearring geometry, create a GML linearring.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
- *
- * Returns:
- * {DOMElement} A GML linearring node.
- */
- linearring: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:LinearRing");
- gml.appendChild(this.buildCoordinatesNode(geometry));
- return gml;
- },
-
- /**
- * Method: buildGeometry.polygon
- * Given an OpenLayers polygon geometry, create a GML polygon.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
- *
- * Returns:
- * {DOMElement} A GML polygon node.
- */
- polygon: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:Polygon");
- var rings = geometry.components;
- var ringMember, ringGeom, type;
- for(var i=0; i<rings.length; ++i) {
- type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
- ringMember = this.createElementNS(this.gmlns,
- "gml:" + type);
- ringGeom = this.buildGeometry.linearring.apply(this,
- [rings[i]]);
- ringMember.appendChild(ringGeom);
- gml.appendChild(ringMember);
- }
- return gml;
- },
-
- /**
- * Method: buildGeometry.multipolygon
- * Given an OpenLayers multipolygon geometry, create a GML multipolygon.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon
- * geometry.
- *
- * Returns:
- * {DOMElement} A GML multipolygon node.
- */
- multipolygon: function(geometry) {
- var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon");
- var polys = geometry.components;
- var polyMember, polyGeom;
- for(var i=0; i<polys.length; ++i) {
- polyMember = this.createElementNS(this.gmlns,
- "gml:polygonMember");
- polyGeom = this.buildGeometry.polygon.apply(this,
- [polys[i]]);
- polyMember.appendChild(polyGeom);
- gml.appendChild(polyMember);
- }
- return gml;
-
- },
-
- /**
- * Method: buildGeometry.bounds
- * Given an OpenLayers bounds, create a GML box.
- *
- * Parameters:
- * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object.
- *
- * Returns:
- * {DOMElement} A GML box node.
- */
- bounds: function(bounds) {
- var gml = this.createElementNS(this.gmlns, "gml:Box");
- gml.appendChild(this.buildCoordinatesNode(bounds));
- return gml;
- }
- },
-
- /**
- * Method: buildCoordinates
- * builds the coordinates XmlNode
- * (code)
- * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
- * (end)
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {XmlNode} created xmlNode
- */
- buildCoordinatesNode: function(geometry) {
- var coordinatesNode = this.createElementNS(this.gmlns,
- "gml:coordinates");
- coordinatesNode.setAttribute("decimal", ".");
- coordinatesNode.setAttribute("cs", ",");
- coordinatesNode.setAttribute("ts", " ");
-
- var parts = [];
-
- if(geometry instanceof OpenLayers.Bounds){
- parts.push(geometry.left + "," + geometry.bottom);
- parts.push(geometry.right + "," + geometry.top);
- } else {
- var points = (geometry.components) ? geometry.components : [geometry];
- for(var i=0; i<points.length; i++) {
- parts.push(points[i].x + "," + points[i].y);
- }
- }
-
- var txtNode = this.createTextNode(parts.join(" "));
- coordinatesNode.appendChild(txtNode);
-
- return coordinatesNode;
- },
-
- CLASS_NAME: "OpenLayers.Format.GML"
-});
-/* ======================================================================
- OpenLayers/Format/GML/Base.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Format/GML.js
- */
-
-/**
- * Though required in the full build, if the GML format is excluded, we set
- * the namespace here.
- */
-if(!OpenLayers.Format.GML) {
- OpenLayers.Format.GML = {};
-}
-
-/**
- * Class: OpenLayers.Format.GML.Base
- * Superclass for GML parsers.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- gml: "http://www.opengis.net/gml",
- xlink: "http://www.w3.org/1999/xlink",
- xsi: "http://www.w3.org/2001/XMLSchema-instance",
- wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
- },
-
- /**
- * Property: defaultPrefix
- */
- defaultPrefix: "gml",
-
- /**
- * Property: schemaLocation
- * {String} Schema location for a particular minor version.
- */
- schemaLocation: null,
-
- /**
- * APIProperty: featureType
- * {Array(String) or String} The local (without prefix) feature typeName(s).
- */
- featureType: null,
-
- /**
- * APIProperty: featureNS
- * {String} The feature namespace. Must be set in the options at
- * construction.
- */
- featureNS: null,
-
- /**
- * APIProperty: geometry
- * {String} Name of geometry element. Defaults to "geometry". If null, it
- * will be set on <read> when the first geometry is parsed.
- */
- geometryName: "geometry",
-
- /**
- * APIProperty: extractAttributes
- * {Boolean} Extract attributes from GML. Default is true.
- */
- extractAttributes: true,
-
- /**
- * APIProperty: srsName
- * {String} URI for spatial reference system. This is optional for
- * single part geometries and mandatory for collections and multis.
- * If set, the srsName attribute will be written for all geometries.
- * Default is null.
- */
- srsName: null,
-
- /**
- * 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: geometryTypes
- * {Object} Maps OpenLayers geometry class names to GML element names.
- * Use <setGeometryTypes> before accessing this property.
- */
- geometryTypes: null,
-
- /**
- * Property: singleFeatureType
- * {Boolean} True if there is only 1 featureType, and not an array
- * of featuretypes.
- */
- singleFeatureType: null,
-
- /**
- * Property: autoConfig
- * {Boolean} Indicates if the format was configured without a <featureNS>,
- * but auto-configured <featureNS> and <featureType> during read.
- * Subclasses making use of <featureType> auto-configuration should make
- * the first call to the <readNode> method (usually in the read method)
- * with true as 3rd argument, so the auto-configured featureType can be
- * reset and the format can be reused for subsequent reads with data from
- * different featureTypes. Set to false after read if you want to keep the
- * auto-configured values.
- */
-
- /**
- * Property: regExes
- * Compiled regular expressions for manipulating strings.
- */
- regExes: {
- trimSpace: (/^\s*|\s*$/g),
- removeSpace: (/\s*/g),
- splitSpace: (/\s+/),
- trimComma: (/\s*,\s*/g),
- featureMember: (/^(.*:)?featureMembers?$/)
- },
-
- /**
- * Constructor: OpenLayers.Format.GML.Base
- * Instances of this class are not created directly. Use the
- * <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor
- * instead.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- *
- * Valid options properties:
- * featureType - {Array(String) or String} Local (without prefix) feature
- * typeName(s) (required for write).
- * featureNS - {String} Feature namespace (required for write).
- * geometryName - {String} Geometry element name (required for write).
- */
- initialize: function(options) {
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- this.setGeometryTypes();
- if(options && options.featureNS) {
- this.setNamespace("feature", options.featureNS);
- }
- this.singleFeatureType = !options || (typeof options.featureType === "string");
- },
-
- /**
- * Method: read
- *
- * Parameters:
- * data - {DOMElement} A gml:featureMember element, a gml:featureMembers
- * element, or an element containing either of the above at any level.
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} An array of features.
- */
- read: function(data) {
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
- if(data && data.nodeType == 9) {
- data = data.documentElement;
- }
- var features = [];
- this.readNode(data, {features: features}, true);
- if(features.length == 0) {
- // look for gml:featureMember elements
- var elements = this.getElementsByTagNameNS(
- data, this.namespaces.gml, "featureMember"
- );
- if(elements.length) {
- for(var i=0, len=elements.length; i<len; ++i) {
- this.readNode(elements[i], {features: features}, true);
- }
- } else {
- // look for gml:featureMembers elements (this is v3, but does no harm here)
- var elements = this.getElementsByTagNameNS(
- data, this.namespaces.gml, "featureMembers"
- );
- if(elements.length) {
- // there can be only one
- this.readNode(elements[0], {features: features}, true);
- }
- }
- }
- return features;
- },
-
- /**
- * 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).
- * first - {Boolean} Should be set to true for the first node read. This
- * is usually the readNode call in the read method. Without this being
- * set, auto-configured properties will stick on subsequent reads.
- *
- * Returns:
- * {Object} The input object, modified (or a new one if none was provided).
- */
- readNode: function(node, obj, first) {
- // on subsequent calls of format.read(), we want to reset auto-
- // configured properties and auto-configure again.
- if (first === true && this.autoConfig === true) {
- this.featureType = null;
- delete this.namespaceAlias[this.featureNS];
- delete this.namespaces["feature"];
- this.featureNS = null;
- }
- // featureType auto-configuration
- if (!this.featureNS && (!(node.prefix in this.namespaces) &&
- node.parentNode.namespaceURI == this.namespaces["gml"] &&
- this.regExes.featureMember.test(node.parentNode.nodeName))) {
- this.featureType = node.nodeName.split(":").pop();
- this.setNamespace("feature", node.namespaceURI);
- this.featureNS = node.namespaceURI;
- this.autoConfig = true;
- }
- return OpenLayers.Format.XML.prototype.readNode.apply(this, [node, 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: {
- "gml": {
- "_inherit": function(node, obj, container) {
- // To be implemented by version specific parsers
- },
- "featureMember": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "featureMembers": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "name": function(node, obj) {
- obj.name = this.getChildValue(node);
- },
- "boundedBy": function(node, obj) {
- var container = {};
- this.readChildNodes(node, container);
- if(container.components && container.components.length > 0) {
- obj.bounds = container.components[0];
- }
- },
- "Point": function(node, container) {
- var obj = {points: []};
- this.readChildNodes(node, obj);
- if(!container.components) {
- container.components = [];
- }
- container.components.push(obj.points[0]);
- },
- "coordinates": function(node, obj) {
- var str = this.getChildValue(node).replace(
- this.regExes.trimSpace, ""
- );
- str = str.replace(this.regExes.trimComma, ",");
- var pointList = str.split(this.regExes.splitSpace);
- var coords;
- var numPoints = pointList.length;
- var points = new Array(numPoints);
- for(var i=0; i<numPoints; ++i) {
- coords = pointList[i].split(",");
- if (this.xy) {
- points[i] = new OpenLayers.Geometry.Point(
- coords[0], coords[1], coords[2]
- );
- } else {
- points[i] = new OpenLayers.Geometry.Point(
- coords[1], coords[0], coords[2]
- );
- }
- }
- obj.points = points;
- },
- "coord": function(node, obj) {
- var coord = {};
- this.readChildNodes(node, coord);
- if(!obj.points) {
- obj.points = [];
- }
- obj.points.push(new OpenLayers.Geometry.Point(
- coord.x, coord.y, coord.z
- ));
- },
- "X": function(node, coord) {
- coord.x = this.getChildValue(node);
- },
- "Y": function(node, coord) {
- coord.y = this.getChildValue(node);
- },
- "Z": function(node, coord) {
- coord.z = this.getChildValue(node);
- },
- "MultiPoint": function(node, container) {
- var obj = {components: []};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- container.components = [
- new OpenLayers.Geometry.MultiPoint(obj.components)
- ];
- },
- "pointMember": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "LineString": function(node, container) {
- var obj = {};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- if(!container.components) {
- container.components = [];
- }
- container.components.push(
- new OpenLayers.Geometry.LineString(obj.points)
- );
- },
- "MultiLineString": function(node, container) {
- var obj = {components: []};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- container.components = [
- new OpenLayers.Geometry.MultiLineString(obj.components)
- ];
- },
- "lineStringMember": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "Polygon": function(node, container) {
- var obj = {outer: null, inner: []};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- obj.inner.unshift(obj.outer);
- if(!container.components) {
- container.components = [];
- }
- container.components.push(
- new OpenLayers.Geometry.Polygon(obj.inner)
- );
- },
- "LinearRing": function(node, obj) {
- var container = {};
- this.readers.gml._inherit.apply(this, [node, container]);
- this.readChildNodes(node, container);
- obj.components = [new OpenLayers.Geometry.LinearRing(
- container.points
- )];
- },
- "MultiPolygon": function(node, container) {
- var obj = {components: []};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- container.components = [
- new OpenLayers.Geometry.MultiPolygon(obj.components)
- ];
- },
- "polygonMember": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "GeometryCollection": function(node, container) {
- var obj = {components: []};
- this.readers.gml._inherit.apply(this, [node, obj, container]);
- this.readChildNodes(node, obj);
- container.components = [
- new OpenLayers.Geometry.Collection(obj.components)
- ];
- },
- "geometryMember": function(node, obj) {
- this.readChildNodes(node, obj);
- }
- },
- "feature": {
- "*": function(node, obj) {
- // The node can either be named like the featureType, or it
- // can be a child of the feature:featureType. Children can be
- // geometry or attributes.
- var name;
- var local = node.localName || node.nodeName.split(":").pop();
- // Since an attribute can have the same name as the feature type
- // we only want to read the node as a feature if the parent
- // node can have feature nodes as children. In this case, the
- // obj.features property is set.
- if (obj.features) {
- if (!this.singleFeatureType &&
- (OpenLayers.Util.indexOf(this.featureType, local) !== -1)) {
- name = "_typeName";
- } else if(local === this.featureType) {
- name = "_typeName";
- }
- } else {
- // Assume attribute elements have one child node and that the child
- // is a text node. Otherwise assume it is a geometry node.
- if(node.childNodes.length == 0 ||
- (node.childNodes.length == 1 && node.firstChild.nodeType == 3)) {
- if(this.extractAttributes) {
- name = "_attribute";
- }
- } else {
- name = "_geometry";
- }
- }
- if(name) {
- this.readers.feature[name].apply(this, [node, obj]);
- }
- },
- "_typeName": function(node, obj) {
- var container = {components: [], attributes: {}};
- this.readChildNodes(node, container);
- // look for common gml namespaced elements
- if(container.name) {
- container.attributes.name = container.name;
- }
- var feature = new OpenLayers.Feature.Vector(
- container.components[0], container.attributes
- );
- if (!this.singleFeatureType) {
- feature.type = node.nodeName.split(":").pop();
- feature.namespace = node.namespaceURI;
- }
- var fid = node.getAttribute("fid") ||
- this.getAttributeNS(node, this.namespaces["gml"], "id");
- if(fid) {
- feature.fid = fid;
- }
- if(this.internalProjection && this.externalProjection &&
- feature.geometry) {
- feature.geometry.transform(
- this.externalProjection, this.internalProjection
- );
- }
- if(container.bounds) {
- feature.bounds = container.bounds;
- }
- obj.features.push(feature);
- },
- "_geometry": function(node, obj) {
- if (!this.geometryName) {
- this.geometryName = node.nodeName.split(":").pop();
- }
- this.readChildNodes(node, obj);
- },
- "_attribute": function(node, obj) {
- var local = node.localName || node.nodeName.split(":").pop();
- var value = this.getChildValue(node);
- obj.attributes[local] = value;
- }
- },
- "wfs": {
- "FeatureCollection": function(node, obj) {
- this.readChildNodes(node, obj);
- }
- }
- },
-
- /**
- * Method: write
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
- * An array of features or a single feature.
- *
- * Returns:
- * {String} Given an array of features, a doc with a gml:featureMembers
- * element will be returned. Given a single feature, a doc with a
- * gml:featureMember element will be returned.
- */
- write: function(features) {
- var name;
- if(OpenLayers.Util.isArray(features)) {
- name = "featureMembers";
- } else {
- name = "featureMember";
- }
- var root = this.writeNode("gml:" + name, features);
- this.setAttributeNS(
- root, this.namespaces["xsi"],
- "xsi:schemaLocation", this.schemaLocation
- );
-
- return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
- },
-
- /**
- * 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: {
- "gml": {
- "featureMember": function(feature) {
- var node = this.createElementNSPlus("gml:featureMember");
- this.writeNode("feature:_typeName", feature, node);
- return node;
- },
- "MultiPoint": function(geometry) {
- var node = this.createElementNSPlus("gml:MultiPoint");
- var components = geometry.components || [geometry];
- for(var i=0, ii=components.length; i<ii; ++i) {
- this.writeNode("pointMember", components[i], node);
- }
- return node;
- },
- "pointMember": function(geometry) {
- var node = this.createElementNSPlus("gml:pointMember");
- this.writeNode("Point", geometry, node);
- return node;
- },
- "MultiLineString": function(geometry) {
- var node = this.createElementNSPlus("gml:MultiLineString");
- var components = geometry.components || [geometry];
- for(var i=0, ii=components.length; i<ii; ++i) {
- this.writeNode("lineStringMember", components[i], node);
- }
- return node;
- },
- "lineStringMember": function(geometry) {
- var node = this.createElementNSPlus("gml:lineStringMember");
- this.writeNode("LineString", geometry, node);
- return node;
- },
- "MultiPolygon": function(geometry) {
- var node = this.createElementNSPlus("gml:MultiPolygon");
- var components = geometry.components || [geometry];
- for(var i=0, ii=components.length; i<ii; ++i) {
- this.writeNode(
- "polygonMember", components[i], node
- );
- }
- return node;
- },
- "polygonMember": function(geometry) {
- var node = this.createElementNSPlus("gml:polygonMember");
- this.writeNode("Polygon", geometry, node);
- return node;
- },
- "GeometryCollection": function(geometry) {
- var node = this.createElementNSPlus("gml:GeometryCollection");
- for(var i=0, len=geometry.components.length; i<len; ++i) {
- this.writeNode("geometryMember", geometry.components[i], node);
- }
- return node;
- },
- "geometryMember": function(geometry) {
- var node = this.createElementNSPlus("gml:geometryMember");
- var child = this.writeNode("feature:_geometry", geometry);
- node.appendChild(child.firstChild);
- return node;
- }
- },
- "feature": {
- "_typeName": function(feature) {
- var node = this.createElementNSPlus("feature:" + this.featureType, {
- attributes: {fid: feature.fid}
- });
- if(feature.geometry) {
- this.writeNode("feature:_geometry", feature.geometry, node);
- }
- for(var name in feature.attributes) {
- var value = feature.attributes[name];
- if(value != null) {
- this.writeNode(
- "feature:_attribute",
- {name: name, value: value}, node
- );
- }
- }
- return node;
- },
- "_geometry": function(geometry) {
- if(this.externalProjection && this.internalProjection) {
- geometry = geometry.clone().transform(
- this.internalProjection, this.externalProjection
- );
- }
- var node = this.createElementNSPlus(
- "feature:" + this.geometryName
- );
- var type = this.geometryTypes[geometry.CLASS_NAME];
- var child = this.writeNode("gml:" + type, geometry, node);
- if(this.srsName) {
- child.setAttribute("srsName", this.srsName);
- }
- return node;
- },
- "_attribute": function(obj) {
- return this.createElementNSPlus("feature:" + obj.name, {
- value: obj.value
- });
- }
- },
- "wfs": {
- "FeatureCollection": function(features) {
- /**
- * This is only here because GML2 only describes abstract
- * feature collections. Typically, you would not be using
- * the GML format to write wfs elements. This just provides
- * some way to write out lists of features. GML3 defines the
- * featureMembers element, so that is used by default instead.
- */
- var node = this.createElementNSPlus("wfs:FeatureCollection");
- for(var i=0, len=features.length; i<len; ++i) {
- this.writeNode("gml:featureMember", features[i], node);
- }
- return node;
- }
- }
- },
-
- /**
- * Method: setGeometryTypes
- * Sets the <geometryTypes> mapping.
- */
- setGeometryTypes: function() {
- this.geometryTypes = {
- "OpenLayers.Geometry.Point": "Point",
- "OpenLayers.Geometry.MultiPoint": "MultiPoint",
- "OpenLayers.Geometry.LineString": "LineString",
- "OpenLayers.Geometry.MultiLineString": "MultiLineString",
- "OpenLayers.Geometry.Polygon": "Polygon",
- "OpenLayers.Geometry.MultiPolygon": "MultiPolygon",
- "OpenLayers.Geometry.Collection": "GeometryCollection"
- };
- },
-
- CLASS_NAME: "OpenLayers.Format.GML.Base"
-
-});
-/* ======================================================================
- OpenLayers/Format/GML/v2.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/GML/Base.js
- */
-
-/**
- * Class: OpenLayers.Format.GML.v2
- * Parses GML version 2.
- *
- * Inherits from:
- * - <OpenLayers.Format.GML.Base>
- */
-OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
-
- /**
- * Property: schemaLocation
- * {String} Schema location for a particular minor version.
- */
- schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
-
- /**
- * Constructor: OpenLayers.Format.GML.v2
- * Create a parser for GML v2.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- *
- * Valid options properties:
- * featureType - {String} Local (without prefix) feature typeName (required).
- * featureNS - {String} Feature namespace (required).
- * geometryName - {String} Geometry element name.
- */
- initialize: function(options) {
- OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * 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: {
- "gml": OpenLayers.Util.applyDefaults({
- "outerBoundaryIs": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- container.outer = obj.components[0];
- },
- "innerBoundaryIs": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- container.inner.push(obj.components[0]);
- },
- "Box": function(node, container) {
- var obj = {};
- this.readChildNodes(node, obj);
- if(!container.components) {
- container.components = [];
- }
- var min = obj.points[0];
- var max = obj.points[1];
- container.components.push(
- new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
- );
- }
- }, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
- "feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
- "wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
- },
-
- /**
- * Method: write
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
- * An array of features or a single feature.
- *
- * Returns:
- * {String} Given an array of features, a doc with a gml:featureMembers
- * element will be returned. Given a single feature, a doc with a
- * gml:featureMember element will be returned.
- */
- write: function(features) {
- var name;
- if(OpenLayers.Util.isArray(features)) {
- // GML2 only has abstract feature collections
- // wfs provides a feature collection from a well-known schema
- name = "wfs:FeatureCollection";
- } else {
- name = "gml:featureMember";
- }
- var root = this.writeNode(name, features);
- this.setAttributeNS(
- root, this.namespaces["xsi"],
- "xsi:schemaLocation", this.schemaLocation
- );
-
- return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
- },
-
- /**
- * 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: {
- "gml": OpenLayers.Util.applyDefaults({
- "Point": function(geometry) {
- var node = this.createElementNSPlus("gml:Point");
- this.writeNode("coordinates", [geometry], node);
- return node;
- },
- "coordinates": function(points) {
- var numPoints = points.length;
- var parts = new Array(numPoints);
- var point;
- for(var i=0; i<numPoints; ++i) {
- point = points[i];
- if(this.xy) {
- parts[i] = point.x + "," + point.y;
- } else {
- parts[i] = point.y + "," + point.x;
- }
- if(point.z != undefined) { // allow null or undefined
- parts[i] += "," + point.z;
- }
- }
- return this.createElementNSPlus("gml:coordinates", {
- attributes: {
- decimal: ".", cs: ",", ts: " "
- },
- value: (numPoints == 1) ? parts[0] : parts.join(" ")
- });
- },
- "LineString": function(geometry) {
- var node = this.createElementNSPlus("gml:LineString");
- this.writeNode("coordinates", geometry.components, node);
- return node;
- },
- "Polygon": function(geometry) {
- var node = this.createElementNSPlus("gml:Polygon");
- this.writeNode("outerBoundaryIs", geometry.components[0], node);
- for(var i=1; i<geometry.components.length; ++i) {
- this.writeNode(
- "innerBoundaryIs", geometry.components[i], node
- );
- }
- return node;
- },
- "outerBoundaryIs": function(ring) {
- var node = this.createElementNSPlus("gml:outerBoundaryIs");
- this.writeNode("LinearRing", ring, node);
- return node;
- },
- "innerBoundaryIs": function(ring) {
- var node = this.createElementNSPlus("gml:innerBoundaryIs");
- this.writeNode("LinearRing", ring, node);
- return node;
- },
- "LinearRing": function(ring) {
- var node = this.createElementNSPlus("gml:LinearRing");
- this.writeNode("coordinates", ring.components, node);
- return node;
- },
- "Box": function(bounds) {
- var node = this.createElementNSPlus("gml:Box");
- this.writeNode("coordinates", [
- {x: bounds.left, y: bounds.bottom},
- {x: bounds.right, y: bounds.top}
- ], node);
- // srsName attribute is optional for gml:Box
- if(this.srsName) {
- node.setAttribute("srsName", this.srsName);
- }
- return node;
- }
- }, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
- "feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
- "wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
- },
-
- CLASS_NAME: "OpenLayers.Format.GML.v2"
-
-});
-/* ======================================================================
- OpenLayers/Filter/Function.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Filter.js
- */
-
-/**
- * Class: OpenLayers.Filter.Function
- * This class represents a filter function.
- * We are using this class for creation of complex
- * filters that can contain filter functions as values.
- * Nesting function as other functions parameter is supported.
- *
- * Inherits from:
- * - <OpenLayers.Filter>
- */
-OpenLayers.Filter.Function = OpenLayers.Class(OpenLayers.Filter, {
-
- /**
- * APIProperty: name
- * {String} Name of the function.
- */
- name: null,
-
- /**
- * APIProperty: params
- * {Array(<OpenLayers.Filter.Function> || String || Number)} Function parameters
- * For now support only other Functions, String or Number
- */
- params: null,
-
- /**
- * Constructor: OpenLayers.Filter.Function
- * Creates a filter function.
- *
- * Parameters:
- * options - {Object} An optional object with properties to set on the
- * function.
- *
- * Returns:
- * {<OpenLayers.Filter.Function>}
- */
-
- CLASS_NAME: "OpenLayers.Filter.Function"
-});
-
-/* ======================================================================
- OpenLayers/BaseTypes/Date.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/SingleFile.js
- */
-
-/**
- * Namespace: OpenLayers.Date
- * Contains implementations of Date.parse and date.toISOString that match the
- * ECMAScript 5 specification for parsing RFC 3339 dates.
- * http://tools.ietf.org/html/rfc3339
- */
-OpenLayers.Date = {
-
- /**
- * APIProperty: dateRegEx
- * The regex to be used for validating dates. You can provide your own
- * regex for instance for adding support for years before BC. Default
- * value is: /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/
- */
- dateRegEx: /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/,
-
- /**
- * APIMethod: toISOString
- * Generates a string representing a date. The format of the string follows
- * the profile of ISO 8601 for date and time on the Internet (see
- * http://tools.ietf.org/html/rfc3339). If the toISOString method is
- * available on the Date prototype, that is used. The toISOString
- * method for Date instances is defined in ECMA-262.
- *
- * Parameters:
- * date - {Date} A date object.
- *
- * Returns:
- * {String} A string representing the date (e.g.
- * "2010-08-07T16:58:23.123Z"). If the date does not have a valid time
- * (i.e. isNaN(date.getTime())) this method returns the string "Invalid
- * Date". The ECMA standard says the toISOString method should throw
- * RangeError in this case, but Firefox returns a string instead. For
- * best results, use isNaN(date.getTime()) to determine date validity
- * before generating date strings.
- */
- toISOString: (function() {
- if ("toISOString" in Date.prototype) {
- return function(date) {
- return date.toISOString();
- };
- } else {
- return function(date) {
- var str;
- if (isNaN(date.getTime())) {
- // ECMA-262 says throw RangeError, Firefox returns
- // "Invalid Date"
- str = "Invalid Date";
- } else {
- str =
- date.getUTCFullYear() + "-" +
- OpenLayers.Number.zeroPad(date.getUTCMonth() + 1, 2) + "-" +
- OpenLayers.Number.zeroPad(date.getUTCDate(), 2) + "T" +
- OpenLayers.Number.zeroPad(date.getUTCHours(), 2) + ":" +
- OpenLayers.Number.zeroPad(date.getUTCMinutes(), 2) + ":" +
- OpenLayers.Number.zeroPad(date.getUTCSeconds(), 2) + "." +
- OpenLayers.Number.zeroPad(date.getUTCMilliseconds(), 3) + "Z";
- }
- return str;
- };
- }
-
- })(),
-
- /**
- * APIMethod: parse
- * Generate a date object from a string. The format for the string follows
- * the profile of ISO 8601 for date and time on the Internet (see
- * http://tools.ietf.org/html/rfc3339). We don't call the native
- * Date.parse because of inconsistency between implmentations. In
- * Chrome, calling Date.parse with a string that doesn't contain any
- * indication of the timezone (e.g. "2011"), the date is interpreted
- * in local time. On Firefox, the assumption is UTC.
- *
- * Parameters:
- * str - {String} A string representing the date (e.g.
- * "2010", "2010-08", "2010-08-07", "2010-08-07T16:58:23.123Z",
- * "2010-08-07T11:58:23.123-06").
- *
- * Returns:
- * {Date} A date object. If the string could not be parsed, an invalid
- * date is returned (i.e. isNaN(date.getTime())).
- */
- parse: function(str) {
- var date;
- var match = str.match(this.dateRegEx);
- if (match && (match[1] || match[7])) { // must have at least year or time
- var year = parseInt(match[1], 10) || 0;
- var month = (parseInt(match[2], 10) - 1) || 0;
- var day = parseInt(match[3], 10) || 1;
- date = new Date(Date.UTC(year, month, day));
- // optional time
- var type = match[7];
- if (type) {
- var hours = parseInt(match[4], 10);
- var minutes = parseInt(match[5], 10);
- var secFrac = parseFloat(match[6]);
- var seconds = secFrac | 0;
- var milliseconds = Math.round(1000 * (secFrac - seconds));
- date.setUTCHours(hours, minutes, seconds, milliseconds);
- // check offset
- if (type !== "Z") {
- var hoursOffset = parseInt(type, 10);
- var minutesOffset = parseInt(match[8], 10) || 0;
- var offset = -1000 * (60 * (hoursOffset * 60) + minutesOffset * 60);
- date = new Date(date.getTime() + offset);
- }
- }
- } else {
- date = new Date("invalid");
- }
- return date;
- }
-};
-/* ======================================================================
- OpenLayers/Format/Filter/v1.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-/**
- * @requires OpenLayers/Format/Filter.js
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Filter/Function.js
- * @requires OpenLayers/BaseTypes/Date.js
- */
-
-/**
- * Class: OpenLayers.Format.Filter.v1
- * Superclass for Filter version 1 parsers.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- ogc: "http://www.opengis.net/ogc",
- gml: "http://www.opengis.net/gml",
- xlink: "http://www.w3.org/1999/xlink",
- xsi: "http://www.w3.org/2001/XMLSchema-instance"
- },
-
- /**
- * Property: defaultPrefix
- */
- defaultPrefix: "ogc",
-
- /**
- * Property: schemaLocation
- * {String} Schema location for a particular minor version.
- */
- schemaLocation: null,
-
- /**
- * Constructor: OpenLayers.Format.Filter.v1
- * Instances of this class are not created directly. Use the
- * <OpenLayers.Format.Filter> constructor instead.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(options) {
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * Method: read
- *
- * Parameters:
- * data - {DOMElement} A Filter document element.
- *
- * Returns:
- * {<OpenLayers.Filter>} A filter object.
- */
- read: function(data) {
- var obj = {};
- this.readers.ogc["Filter"].apply(this, [data, obj]);
- return obj.filter;
- },
-
- /**
- * 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": {
- "_expression": function(node) {
- // only the simplest of ogc:expression handled
- // "some text and an <PropertyName>attribute</PropertyName>"}
- var obj, value = "";
- for(var child=node.firstChild; child; child=child.nextSibling) {
- switch(child.nodeType) {
- case 1:
- obj = this.readNode(child);
- if (obj.property) {
- value += "${" + obj.property + "}";
- } else if (obj.value !== undefined) {
- value += obj.value;
- }
- break;
- case 3: // text node
- case 4: // cdata section
- value += child.nodeValue;
- }
- }
- return value;
- },
- "Filter": function(node, parent) {
- // Filters correspond to subclasses of OpenLayers.Filter.
- // Since they contain information we don't persist, we
- // create a temporary object and then pass on the filter
- // (ogc:Filter) to the parent obj.
- var obj = {
- fids: [],
- filters: []
- };
- this.readChildNodes(node, obj);
- if(obj.fids.length > 0) {
- parent.filter = new OpenLayers.Filter.FeatureId({
- fids: obj.fids
- });
- } else if(obj.filters.length > 0) {
- parent.filter = obj.filters[0];
- }
- },
- "FeatureId": function(node, obj) {
- var fid = node.getAttribute("fid");
- if(fid) {
- obj.fids.push(fid);
- }
- },
- "And": function(node, obj) {
- var filter = new OpenLayers.Filter.Logical({
- type: OpenLayers.Filter.Logical.AND
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "Or": function(node, obj) {
- var filter = new OpenLayers.Filter.Logical({
- type: OpenLayers.Filter.Logical.OR
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "Not": function(node, obj) {
- var filter = new OpenLayers.Filter.Logical({
- type: OpenLayers.Filter.Logical.NOT
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsLessThan": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.LESS_THAN
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsGreaterThan": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.GREATER_THAN
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsLessThanOrEqualTo": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsGreaterThanOrEqualTo": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsBetween": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.BETWEEN
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "Literal": function(node, obj) {
- obj.value = OpenLayers.String.numericIf(
- this.getChildValue(node), true);
- },
- "PropertyName": function(node, filter) {
- filter.property = this.getChildValue(node);
- },
- "LowerBoundary": function(node, filter) {
- filter.lowerBoundary = OpenLayers.String.numericIf(
- this.readers.ogc._expression.call(this, node), true);
- },
- "UpperBoundary": function(node, filter) {
- filter.upperBoundary = OpenLayers.String.numericIf(
- this.readers.ogc._expression.call(this, node), true);
- },
- "Intersects": function(node, obj) {
- this.readSpatial(node, obj, OpenLayers.Filter.Spatial.INTERSECTS);
- },
- "Within": function(node, obj) {
- this.readSpatial(node, obj, OpenLayers.Filter.Spatial.WITHIN);
- },
- "Contains": function(node, obj) {
- this.readSpatial(node, obj, OpenLayers.Filter.Spatial.CONTAINS);
- },
- "DWithin": function(node, obj) {
- this.readSpatial(node, obj, OpenLayers.Filter.Spatial.DWITHIN);
- },
- "Distance": function(node, obj) {
- obj.distance = parseInt(this.getChildValue(node));
- obj.distanceUnits = node.getAttribute("units");
- },
- "Function": function(node, obj) {
- //TODO write decoder for it
- return;
- },
- "PropertyIsNull": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.IS_NULL
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- }
- }
- },
-
- /**
- * Method: readSpatial
- *
- * Read a {<OpenLayers.Filter.Spatial>} filter.
- *
- * Parameters:
- * node - {DOMElement} A DOM element that contains an ogc:expression.
- * obj - {Object} The target object.
- * type - {String} One of the OpenLayers.Filter.Spatial.* constants.
- *
- * Returns:
- * {<OpenLayers.Filter.Spatial>} The created filter.
- */
- readSpatial: function(node, obj, type) {
- var filter = new OpenLayers.Filter.Spatial({
- type: type
- });
- this.readChildNodes(node, filter);
- filter.value = filter.components[0];
- delete filter.components;
- obj.filters.push(filter);
- },
-
- /**
- * APIMethod: encodeLiteral
- * Generates the string representation of a value for use in <Literal>
- * elements. The default encoder writes Date values as ISO 8601
- * strings.
- *
- * Parameters:
- * value - {Object} Literal value to encode
- *
- * Returns:
- * {String} String representation of the provided value.
- */
- encodeLiteral: function(value) {
- if (value instanceof Date) {
- value = OpenLayers.Date.toISOString(value);
- }
- return value;
- },
-
- /**
- * Method: writeOgcExpression
- * Limited support for writing OGC expressions. Currently it supports
- * (<OpenLayers.Filter.Function> || String || Number)
- *
- * Parameters:
- * value - (<OpenLayers.Filter.Function> || String || Number)
- * node - {DOMElement} A parent DOM element
- *
- * Returns:
- * {DOMElement} Updated node element.
- */
- writeOgcExpression: function(value, node) {
- if (value instanceof OpenLayers.Filter.Function){
- this.writeNode("Function", value, node);
- } else {
- this.writeNode("Literal", value, node);
- }
- return node;
- },
-
- /**
- * Method: write
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>} A filter object.
- *
- * Returns:
- * {DOMElement} An ogc:Filter element.
- */
- write: function(filter) {
- return this.writers.ogc["Filter"].apply(this, [filter]);
- },
-
- /**
- * 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: {
- "ogc": {
- "Filter": function(filter) {
- var node = this.createElementNSPlus("ogc:Filter");
- this.writeNode(this.getFilterType(filter), filter, node);
- return node;
- },
- "_featureIds": function(filter) {
- var node = this.createDocumentFragment();
- for (var i=0, ii=filter.fids.length; i<ii; ++i) {
- this.writeNode("ogc:FeatureId", filter.fids[i], node);
- }
- return node;
- },
- "FeatureId": function(fid) {
- return this.createElementNSPlus("ogc:FeatureId", {
- attributes: {fid: fid}
- });
- },
- "And": function(filter) {
- var node = this.createElementNSPlus("ogc:And");
- var childFilter;
- for (var i=0, ii=filter.filters.length; i<ii; ++i) {
- childFilter = filter.filters[i];
- this.writeNode(
- this.getFilterType(childFilter), childFilter, node
- );
- }
- return node;
- },
- "Or": function(filter) {
- var node = this.createElementNSPlus("ogc:Or");
- var childFilter;
- for (var i=0, ii=filter.filters.length; i<ii; ++i) {
- childFilter = filter.filters[i];
- this.writeNode(
- this.getFilterType(childFilter), childFilter, node
- );
- }
- return node;
- },
- "Not": function(filter) {
- var node = this.createElementNSPlus("ogc:Not");
- var childFilter = filter.filters[0];
- this.writeNode(
- this.getFilterType(childFilter), childFilter, node
- );
- return node;
- },
- "PropertyIsLessThan": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsLessThan");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsGreaterThan": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsGreaterThan");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsLessThanOrEqualTo": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsGreaterThanOrEqualTo": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsBetween": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsBetween");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- this.writeNode("LowerBoundary", filter, node);
- this.writeNode("UpperBoundary", filter, node);
- return node;
- },
- "PropertyName": function(filter) {
- // no ogc:expression handling for now
- return this.createElementNSPlus("ogc:PropertyName", {
- value: filter.property
- });
- },
- "Literal": function(value) {
- var encode = this.encodeLiteral ||
- OpenLayers.Format.Filter.v1.prototype.encodeLiteral;
- return this.createElementNSPlus("ogc:Literal", {
- value: encode(value)
- });
- },
- "LowerBoundary": function(filter) {
- // handle Literals or Functions for now
- var node = this.createElementNSPlus("ogc:LowerBoundary");
- this.writeOgcExpression(filter.lowerBoundary, node);
- return node;
- },
- "UpperBoundary": function(filter) {
- // handle Literals or Functions for now
- var node = this.createElementNSPlus("ogc:UpperBoundary");
- this.writeNode("Literal", filter.upperBoundary, node);
- return node;
- },
- "INTERSECTS": function(filter) {
- return this.writeSpatial(filter, "Intersects");
- },
- "WITHIN": function(filter) {
- return this.writeSpatial(filter, "Within");
- },
- "CONTAINS": function(filter) {
- return this.writeSpatial(filter, "Contains");
- },
- "DWITHIN": function(filter) {
- var node = this.writeSpatial(filter, "DWithin");
- this.writeNode("Distance", filter, node);
- return node;
- },
- "Distance": function(filter) {
- return this.createElementNSPlus("ogc:Distance", {
- attributes: {
- units: filter.distanceUnits
- },
- value: filter.distance
- });
- },
- "Function": function(filter) {
- var node = this.createElementNSPlus("ogc:Function", {
- attributes: {
- name: filter.name
- }
- });
- var params = filter.params;
- for(var i=0, len=params.length; i<len; i++){
- this.writeOgcExpression(params[i], node);
- }
- return node;
- },
- "PropertyIsNull": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsNull");
- this.writeNode("PropertyName", filter, node);
- return node;
- }
- }
- },
-
- /**
- * Method: getFilterType
- */
- getFilterType: function(filter) {
- var filterType = this.filterMap[filter.type];
- if(!filterType) {
- throw "Filter writing not supported for rule type: " + filter.type;
- }
- return filterType;
- },
-
- /**
- * Property: filterMap
- * {Object} Contains a member for each filter type. Values are node names
- * for corresponding OGC Filter child elements.
- */
- filterMap: {
- "&&": "And",
- "||": "Or",
- "!": "Not",
- "==": "PropertyIsEqualTo",
- "!=": "PropertyIsNotEqualTo",
- "<": "PropertyIsLessThan",
- ">": "PropertyIsGreaterThan",
- "<=": "PropertyIsLessThanOrEqualTo",
- ">=": "PropertyIsGreaterThanOrEqualTo",
- "..": "PropertyIsBetween",
- "~": "PropertyIsLike",
- "NULL": "PropertyIsNull",
- "BBOX": "BBOX",
- "DWITHIN": "DWITHIN",
- "WITHIN": "WITHIN",
- "CONTAINS": "CONTAINS",
- "INTERSECTS": "INTERSECTS",
- "FID": "_featureIds"
- },
-
- CLASS_NAME: "OpenLayers.Format.Filter.v1"
-
-});
-/* ======================================================================
- OpenLayers/Format/Filter/v1_0_0.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/GML/v2.js
- * @requires OpenLayers/Format/Filter/v1.js
- */
-
-/**
- * Class: OpenLayers.Format.Filter.v1_0_0
- * Write ogc:Filter version 1.0.0.
- *
- * Inherits from:
- * - <OpenLayers.Format.GML.v2>
- * - <OpenLayers.Format.Filter.v1>
- */
-OpenLayers.Format.Filter.v1_0_0 = OpenLayers.Class(
- OpenLayers.Format.GML.v2, OpenLayers.Format.Filter.v1, {
-
- /**
- * Constant: VERSION
- * {String} 1.0.0
- */
- VERSION: "1.0.0",
-
- /**
- * Property: schemaLocation
- * {String} http://www.opengis.net/ogc/filter/1.0.0/filter.xsd
- */
- schemaLocation: "http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",
-
- /**
- * Constructor: OpenLayers.Format.Filter.v1_0_0
- * Instances of this class are not created directly. Use the
- * <OpenLayers.Format.Filter> constructor instead.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(options) {
- OpenLayers.Format.GML.v2.prototype.initialize.apply(
- this, [options]
- );
- },
-
- /**
- * 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": OpenLayers.Util.applyDefaults({
- "PropertyIsEqualTo": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.EQUAL_TO
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsNotEqualTo": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.NOT_EQUAL_TO
- });
- this.readChildNodes(node, filter);
- obj.filters.push(filter);
- },
- "PropertyIsLike": function(node, obj) {
- var filter = new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.LIKE
- });
- this.readChildNodes(node, filter);
- var wildCard = node.getAttribute("wildCard");
- var singleChar = node.getAttribute("singleChar");
- var esc = node.getAttribute("escape");
- filter.value2regex(wildCard, singleChar, esc);
- obj.filters.push(filter);
- }
- }, OpenLayers.Format.Filter.v1.prototype.readers["ogc"]),
- "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"],
- "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"]
- },
-
- /**
- * 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: {
- "ogc": OpenLayers.Util.applyDefaults({
- "PropertyIsEqualTo": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsEqualTo");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsNotEqualTo": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsNotEqualTo");
- // no ogc:expression handling for PropertyName for now
- this.writeNode("PropertyName", filter, node);
- // handle Literals or Functions for now
- this.writeOgcExpression(filter.value, node);
- return node;
- },
- "PropertyIsLike": function(filter) {
- var node = this.createElementNSPlus("ogc:PropertyIsLike", {
- attributes: {
- wildCard: "*", singleChar: ".", escape: "!"
- }
- });
- // no ogc:expression handling for now
- this.writeNode("PropertyName", filter, node);
- // convert regex string to ogc string
- this.writeNode("Literal", filter.regex2value(), node);
- return node;
- },
- "BBOX": function(filter) {
- var node = this.createElementNSPlus("ogc:BBOX");
- // PropertyName is mandatory in 1.0.0, but e.g. GeoServer also
- // accepts filters without it. When this is used with
- // OpenLayers.Protocol.WFS, OpenLayers.Format.WFST will set a
- // missing filter.property to the geometryName that is
- // configured with the protocol, which defaults to "the_geom".
- // So the only way to omit this mandatory property is to not
- // set the property on the filter and to set the geometryName
- // on the WFS protocol to null. The latter also happens when
- // the protocol is configured without a geometryName and a
- // featureNS.
- filter.property && this.writeNode("PropertyName", filter, node);
- var box = this.writeNode("gml:Box", filter.value, node);
- if(filter.projection) {
- box.setAttribute("srsName", filter.projection);
- }
- return node;
- }
- }, OpenLayers.Format.Filter.v1.prototype.writers["ogc"]),
- "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"],
- "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"]
- },
-
- /**
- * Method: writeSpatial
- *
- * Read a {<OpenLayers.Filter.Spatial>} filter and converts it into XML.
- *
- * Parameters:
- * filter - {<OpenLayers.Filter.Spatial>} The filter.
- * name - {String} Name of the generated XML element.
- *
- * Returns:
- * {DOMElement} The created XML element.
- */
- writeSpatial: function(filter, name) {
- var node = this.createElementNSPlus("ogc:"+name);
- this.writeNode("PropertyName", filter, node);
- if(filter.value instanceof OpenLayers.Filter.Function) {
- this.writeNode("Function", filter.value, node);
- } else {
- var child;
- if(filter.value instanceof OpenLayers.Geometry) {
- child = this.writeNode("feature:_geometry", filter.value).firstChild;
- } else {
- child = this.writeNode("gml:Box", filter.value);
- }
- if(filter.projection) {
- child.setAttribute("srsName", filter.projection);
- }
- node.appendChild(child);
- }
- return node;
- },
-
-
- CLASS_NAME: "OpenLayers.Format.Filter.v1_0_0"
-
-});
-/* ======================================================================
- OpenLayers/Format/WFST/v1_0_0.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/WFST/v1.js
- * @requires OpenLayers/Format/Filter/v1_0_0.js
- */
-
-/**
- * Class: OpenLayers.Format.WFST.v1_0_0
- * A format for creating WFS v1.0.0 transactions. Create a new instance with the
- * <OpenLayers.Format.WFST.v1_0_0> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format.Filter.v1_0_0>
- * - <OpenLayers.Format.WFST.v1>
- */
-OpenLayers.Format.WFST.v1_0_0 = OpenLayers.Class(
- OpenLayers.Format.Filter.v1_0_0, OpenLayers.Format.WFST.v1, {
-
- /**
- * Property: version
- * {String} WFS version number.
- */
- version: "1.0.0",
-
- /**
- * APIProperty: srsNameInQuery
- * {Boolean} If true the reference system is passed in Query requests
- * via the "srsName" attribute to the "wfs:Query" element, this
- * property defaults to false as it isn't WFS 1.0.0 compliant.
- */
- srsNameInQuery: false,
-
- /**
- * Property: schemaLocations
- * {Object} Properties are namespace aliases, values are schema locations.
- */
- schemaLocations: {
- "wfs": "http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"
- },
-
- /**
- * Constructor: OpenLayers.Format.WFST.v1_0_0
- * A class for parsing and generating WFS v1.0.0 transactions.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Valid options properties:
- * featureType - {String} Local (without prefix) feature typeName (required).
- * featureNS - {String} Feature namespace (optional).
- * featurePrefix - {String} Feature namespace alias (optional - only used
- * if featureNS is provided). Default is 'feature'.
- * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
- */
- initialize: function(options) {
- OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this, [options]);
- OpenLayers.Format.WFST.v1.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * 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).
- * first - {Boolean} Should be set to true for the first node read. This
- * is usually the readNode call in the read method. Without this being
- * set, auto-configured properties will stick on subsequent reads.
- *
- * Returns:
- * {Object} The input object, modified (or a new one if none was provided).
- */
- readNode: function(node, obj, first) {
- // Not the superclass, only the mixin classes inherit from
- // Format.GML.v2. We need this because we don't want to get readNode
- // from the superclass's superclass, which is OpenLayers.Format.XML.
- return OpenLayers.Format.GML.v2.prototype.readNode.apply(this, arguments);
- },
-
- /**
- * 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": OpenLayers.Util.applyDefaults({
- "WFS_TransactionResponse": function(node, obj) {
- obj.insertIds = [];
- obj.success = false;
- this.readChildNodes(node, obj);
- },
- "InsertResult": function(node, container) {
- var obj = {fids: []};
- this.readChildNodes(node, obj);
- container.insertIds = container.insertIds.concat(obj.fids);
- },
- "TransactionResult": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "Status": function(node, obj) {
- this.readChildNodes(node, obj);
- },
- "SUCCESS": function(node, obj) {
- obj.success = true;
- }
- }, OpenLayers.Format.WFST.v1.prototype.readers["wfs"]),
- "gml": OpenLayers.Format.GML.v2.prototype.readers["gml"],
- "feature": OpenLayers.Format.GML.v2.prototype.readers["feature"],
- "ogc": OpenLayers.Format.Filter.v1_0_0.prototype.readers["ogc"]
- },
-
- /**
- * 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": OpenLayers.Util.applyDefaults({
- "Query": function(options) {
- options = OpenLayers.Util.extend({
- featureNS: this.featureNS,
- featurePrefix: this.featurePrefix,
- featureType: this.featureType,
- srsName: this.srsName,
- srsNameInQuery: this.srsNameInQuery
- }, options);
- var prefix = options.featurePrefix;
- var node = this.createElementNSPlus("wfs:Query", {
- attributes: {
- typeName: (prefix ? prefix + ":" : "") +
- options.featureType
- }
- });
- if(options.srsNameInQuery && options.srsName) {
- node.setAttribute("srsName", options.srsName);
- }
- if(options.featureNS) {
- node.setAttribute("xmlns:" + prefix, options.featureNS);
- }
- if(options.propertyNames) {
- for(var i=0,len = options.propertyNames.length; i<len; i++) {
- this.writeNode(
- "ogc:PropertyName",
- {property: options.propertyNames[i]},
- node
- );
- }
- }
- if(options.filter) {
- this.setFilterProperty(options.filter);
- this.writeNode("ogc:Filter", options.filter, node);
- }
- return node;
- }
- }, OpenLayers.Format.WFST.v1.prototype.writers["wfs"]),
- "gml": OpenLayers.Format.GML.v2.prototype.writers["gml"],
- "feature": OpenLayers.Format.GML.v2.prototype.writers["feature"],
- "ogc": OpenLayers.Format.Filter.v1_0_0.prototype.writers["ogc"]
- },
-
- CLASS_NAME: "OpenLayers.Format.WFST.v1_0_0"
-});
-/* ======================================================================
- OpenLayers/Renderer/Elements.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Renderer.js
- */
-
-/**
- * Class: OpenLayers.ElementsIndexer
- * This class takes care of figuring out which order elements should be
- * placed in the DOM based on given indexing methods.
- */
-OpenLayers.ElementsIndexer = OpenLayers.Class({
-
- /**
- * Property: maxZIndex
- * {Integer} This is the largest-most z-index value for a node
- * contained within the indexer.
- */
- maxZIndex: null,
-
- /**
- * Property: order
- * {Array<String>} This is an array of node id's stored in the
- * order that they should show up on screen. Id's higher up in the
- * array (higher array index) represent nodes with higher z-indeces.
- */
- order: null,
-
- /**
- * Property: indices
- * {Object} This is a hash that maps node ids to their z-index value
- * stored in the indexer. This is done to make finding a nodes z-index
- * value O(1).
- */
- indices: null,
-
- /**
- * Property: compare
- * {Function} This is the function used to determine placement of
- * of a new node within the indexer. If null, this defaults to to
- * the Z_ORDER_DRAWING_ORDER comparison method.
- */
- compare: null,
-
- /**
- * APIMethod: initialize
- * Create a new indexer with
- *
- * Parameters:
- * yOrdering - {Boolean} Whether to use y-ordering.
- */
- initialize: function(yOrdering) {
-
- this.compare = yOrdering ?
- OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER :
- OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;
-
- this.clear();
- },
-
- /**
- * APIMethod: insert
- * Insert a new node into the indexer. In order to find the correct
- * positioning for the node to be inserted, this method uses a binary
- * search. This makes inserting O(log(n)).
- *
- * Parameters:
- * newNode - {DOMElement} The new node to be inserted.
- *
- * Returns
- * {DOMElement} the node before which we should insert our newNode, or
- * null if newNode can just be appended.
- */
- insert: function(newNode) {
- // If the node is known to the indexer, remove it so we can
- // recalculate where it should go.
- if (this.exists(newNode)) {
- this.remove(newNode);
- }
-
- var nodeId = newNode.id;
-
- this.determineZIndex(newNode);
-
- var leftIndex = -1;
- var rightIndex = this.order.length;
- var middle;
-
- while (rightIndex - leftIndex > 1) {
- middle = parseInt((leftIndex + rightIndex) / 2);
-
- var placement = this.compare(this, newNode,
- OpenLayers.Util.getElement(this.order[middle]));
-
- if (placement > 0) {
- leftIndex = middle;
- } else {
- rightIndex = middle;
- }
- }
-
- this.order.splice(rightIndex, 0, nodeId);
- this.indices[nodeId] = this.getZIndex(newNode);
-
- // If the new node should be before another in the index
- // order, return the node before which we have to insert the new one;
- // else, return null to indicate that the new node can be appended.
- return this.getNextElement(rightIndex);
- },
-
- /**
- * APIMethod: remove
- *
- * Parameters:
- * node - {DOMElement} The node to be removed.
- */
- remove: function(node) {
- var nodeId = node.id;
- var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId);
- if (arrayIndex >= 0) {
- // Remove it from the order array, as well as deleting the node
- // from the indeces hash.
- this.order.splice(arrayIndex, 1);
- delete this.indices[nodeId];
-
- // Reset the maxium z-index based on the last item in the
- // order array.
- if (this.order.length > 0) {
- var lastId = this.order[this.order.length - 1];
- this.maxZIndex = this.indices[lastId];
- } else {
- this.maxZIndex = 0;
- }
- }
- },
-
- /**
- * APIMethod: clear
- */
- clear: function() {
- this.order = [];
- this.indices = {};
- this.maxZIndex = 0;
- },
-
- /**
- * APIMethod: exists
- *
- * Parameters:
- * node - {DOMElement} The node to test for existence.
- *
- * Returns:
- * {Boolean} Whether or not the node exists in the indexer?
- */
- exists: function(node) {
- return (this.indices[node.id] != null);
- },
-
- /**
- * APIMethod: getZIndex
- * Get the z-index value for the current node from the node data itself.
- *
- * Parameters:
- * node - {DOMElement} The node whose z-index to get.
- *
- * Returns:
- * {Integer} The z-index value for the specified node (from the node
- * data itself).
- */
- getZIndex: function(node) {
- return node._style.graphicZIndex;
- },
-
- /**
- * Method: determineZIndex
- * Determine the z-index for the current node if there isn't one,
- * and set the maximum value if we've found a new maximum.
- *
- * Parameters:
- * node - {DOMElement}
- */
- determineZIndex: function(node) {
- var zIndex = node._style.graphicZIndex;
-
- // Everything must have a zIndex. If none is specified,
- // this means the user *must* (hint: assumption) want this
- // node to succomb to drawing order. To enforce drawing order
- // over all indexing methods, we'll create a new z-index that's
- // greater than any currently in the indexer.
- if (zIndex == null) {
- zIndex = this.maxZIndex;
- node._style.graphicZIndex = zIndex;
- } else if (zIndex > this.maxZIndex) {
- this.maxZIndex = zIndex;
- }
- },
-
- /**
- * APIMethod: getNextElement
- * Get the next element in the order stack.
- *
- * Parameters:
- * index - {Integer} The index of the current node in this.order.
- *
- * Returns:
- * {DOMElement} the node following the index passed in, or
- * null.
- */
- getNextElement: function(index) {
- var nextIndex = index + 1;
- if (nextIndex < this.order.length) {
- var nextElement = OpenLayers.Util.getElement(this.order[nextIndex]);
- if (nextElement == undefined) {
- nextElement = this.getNextElement(nextIndex);
- }
- return nextElement;
- } else {
- return null;
- }
- },
-
- CLASS_NAME: "OpenLayers.ElementsIndexer"
-});
-
-/**
- * Namespace: OpenLayers.ElementsIndexer.IndexingMethods
- * These are the compare methods for figuring out where a new node should be
- * placed within the indexer. These methods are very similar to general
- * sorting methods in that they return -1, 0, and 1 to specify the
- * direction in which new nodes fall in the ordering.
- */
-OpenLayers.ElementsIndexer.IndexingMethods = {
-
- /**
- * Method: Z_ORDER
- * This compare method is used by other comparison methods.
- * It can be used individually for ordering, but is not recommended,
- * because it doesn't subscribe to drawing order.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER: function(indexer, newNode, nextNode) {
- var newZIndex = indexer.getZIndex(newNode);
-
- var returnVal = 0;
- if (nextNode) {
- var nextZIndex = indexer.getZIndex(nextNode);
- returnVal = newZIndex - nextZIndex;
- }
-
- return returnVal;
- },
-
- /**
- * APIMethod: Z_ORDER_DRAWING_ORDER
- * This method orders nodes by their z-index, but does so in a way
- * that, if there are other nodes with the same z-index, the newest
- * drawn will be the front most within that z-index. This is the
- * default indexing method.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) {
- var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
- indexer,
- newNode,
- nextNode
- );
-
- // Make Z_ORDER subscribe to drawing order by pushing it above
- // all of the other nodes with the same z-index.
- if (nextNode && returnVal == 0) {
- returnVal = 1;
- }
-
- return returnVal;
- },
-
- /**
- * APIMethod: Z_ORDER_Y_ORDER
- * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it
- * best describes which ordering methods have precedence (though, the
- * name would be too long). This method orders nodes by their z-index,
- * but does so in a way that, if there are other nodes with the same
- * z-index, the nodes with the lower y position will be "closer" than
- * those with a higher y position. If two nodes have the exact same y
- * position, however, then this method will revert to using drawing
- * order to decide placement.
- *
- * Parameters:
- * indexer - {<OpenLayers.ElementsIndexer>}
- * newNode - {DOMElement}
- * nextNode - {DOMElement}
- *
- * Returns:
- * {Integer}
- */
- Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) {
- var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(
- indexer,
- newNode,
- nextNode
- );
-
- if (nextNode && returnVal === 0) {
- var result = nextNode._boundsBottom - newNode._boundsBottom;
- returnVal = (result === 0) ? 1 : result;
- }
-
- return returnVal;
- }
-};
-
-/**
- * Class: OpenLayers.Renderer.Elements
- * This is another virtual class in that it should never be instantiated by
- * itself as a Renderer. It exists because there is *tons* of shared
- * functionality between different vector libraries which use nodes/elements
- * as a base for rendering vectors.
- *
- * The highlevel bits of code that are implemented here are the adding and
- * removing of geometries, which is essentially the same for any
- * element-based renderer. The details of creating each node and drawing the
- * paths are of course different, but the machinery is the same.
- *
- * Inherits:
- * - <OpenLayers.Renderer>
- */
-OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
-
- /**
- * Property: rendererRoot
- * {DOMElement}
- */
- rendererRoot: null,
-
- /**
- * Property: root
- * {DOMElement}
- */
- root: null,
-
- /**
- * Property: vectorRoot
- * {DOMElement}
- */
- vectorRoot: null,
-
- /**
- * Property: textRoot
- * {DOMElement}
- */
- textRoot: null,
-
- /**
- * Property: xmlns
- * {String}
- */
- xmlns: null,
-
- /**
- * Property: xOffset
- * {Number} Offset to apply to the renderer viewport translation in x
- * direction. If the renderer extent's center is on the right of the
- * dateline (i.e. exceeds the world bounds), we shift the viewport to the
- * left by one world width. This avoids that features disappear from the
- * map viewport. Because our dateline handling logic in other places
- * ensures that extents crossing the dateline always have a center
- * exceeding the world bounds on the left, we need this offset to make sure
- * that the same is true for the renderer extent in pixel space as well.
- */
- xOffset: 0,
-
- /**
- * Property: rightOfDateLine
- * {Boolean} Keeps track of the location of the map extent relative to the
- * date line. The <setExtent> method compares this value (which is the one
- * from the previous <setExtent> call) with the current position of the map
- * extent relative to the date line and updates the xOffset when the extent
- * has moved from one side of the date line to the other.
- */
-
- /**
- * Property: Indexer
- * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer
- * created upon initialization if the zIndexing or yOrdering options
- * passed to this renderer's constructor are set to true.
- */
- indexer: null,
-
- /**
- * Constant: BACKGROUND_ID_SUFFIX
- * {String}
- */
- BACKGROUND_ID_SUFFIX: "_background",
-
- /**
- * Constant: LABEL_ID_SUFFIX
- * {String}
- */
- LABEL_ID_SUFFIX: "_label",
-
- /**
- * Constant: LABEL_OUTLINE_SUFFIX
- * {String}
- */
- LABEL_OUTLINE_SUFFIX: "_outline",
-
- /**
- * Constructor: OpenLayers.Renderer.Elements
- *
- * Parameters:
- * containerID - {String}
- * options - {Object} options for this renderer.
- *
- * Supported options are:
- * yOrdering - {Boolean} Whether to use y-ordering
- * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
- * if yOrdering is set to true.
- */
- initialize: function(containerID, options) {
- OpenLayers.Renderer.prototype.initialize.apply(this, arguments);
-
- this.rendererRoot = this.createRenderRoot();
- this.root = this.createRoot("_root");
- this.vectorRoot = this.createRoot("_vroot");
- this.textRoot = this.createRoot("_troot");
-
- this.root.appendChild(this.vectorRoot);
- this.root.appendChild(this.textRoot);
-
- this.rendererRoot.appendChild(this.root);
- this.container.appendChild(this.rendererRoot);
-
- if(options && (options.zIndexing || options.yOrdering)) {
- this.indexer = new OpenLayers.ElementsIndexer(options.yOrdering);
- }
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
-
- this.clear();
-
- this.rendererRoot = null;
- this.root = null;
- this.xmlns = null;
-
- OpenLayers.Renderer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clear
- * Remove all the elements from the root
- */
- clear: function() {
- var child;
- var root = this.vectorRoot;
- if (root) {
- while (child = root.firstChild) {
- root.removeChild(child);
- }
- }
- root = this.textRoot;
- if (root) {
- while (child = root.firstChild) {
- root.removeChild(child);
- }
- }
- if (this.indexer) {
- this.indexer.clear();
- }
- },
-
- /**
- * Method: setExtent
- * Set the visible part of the layer.
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- *
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- * False otherwise.
- */
- setExtent: function(extent, resolutionChanged) {
- var coordSysUnchanged = OpenLayers.Renderer.prototype.setExtent.apply(this, arguments);
- var resolution = this.getResolution();
- if (this.map.baseLayer && this.map.baseLayer.wrapDateLine) {
- var rightOfDateLine,
- ratio = extent.getWidth() / this.map.getExtent().getWidth(),
- extent = extent.scale(1 / ratio),
- world = this.map.getMaxExtent();
- if (world.right > extent.left && world.right < extent.right) {
- rightOfDateLine = true;
- } else if (world.left > extent.left && world.left < extent.right) {
- rightOfDateLine = false;
- }
- if (rightOfDateLine !== this.rightOfDateLine || resolutionChanged) {
- coordSysUnchanged = false;
- this.xOffset = rightOfDateLine === true ?
- world.getWidth() / resolution : 0;
- }
- this.rightOfDateLine = rightOfDateLine;
- }
- return coordSysUnchanged;
- },
-
- /**
- * Method: getNodeType
- * This function is in charge of asking the specific renderer which type
- * of node to create for the given geometry and style. All geometries
- * in an Elements-based renderer consist of one node and some
- * attributes. We have the nodeFactory() function which creates a node
- * for us, but it takes a 'type' as input, and that is precisely what
- * this function tells us.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {String} The corresponding node type for the specified geometry
- */
- getNodeType: function(geometry, style) { },
-
- /**
- * Method: drawGeometry
- * Draw the geometry, creating new nodes, setting paths, setting style,
- * setting featureId on the node. This method should only be called
- * by the renderer itself.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the geometry has been drawn completely; null if
- * incomplete; false otherwise
- */
- drawGeometry: function(geometry, style, featureId) {
- var className = geometry.CLASS_NAME;
- var rendered = true;
- if ((className == "OpenLayers.Geometry.Collection") ||
- (className == "OpenLayers.Geometry.MultiPoint") ||
- (className == "OpenLayers.Geometry.MultiLineString") ||
- (className == "OpenLayers.Geometry.MultiPolygon")) {
- for (var i = 0, len=geometry.components.length; i<len; i++) {
- rendered = this.drawGeometry(
- geometry.components[i], style, featureId) && rendered;
- }
- return rendered;
- }
-
- rendered = false;
- var removeBackground = false;
- if (style.display != "none") {
- if (style.backgroundGraphic) {
- this.redrawBackgroundNode(geometry.id, geometry, style,
- featureId);
- } else {
- removeBackground = true;
- }
- rendered = this.redrawNode(geometry.id, geometry, style,
- featureId);
- }
- if (rendered == false) {
- var node = document.getElementById(geometry.id);
- if (node) {
- if (node._style.backgroundGraphic) {
- removeBackground = true;
- }
- node.parentNode.removeChild(node);
- }
- }
- if (removeBackground) {
- var node = document.getElementById(
- geometry.id + this.BACKGROUND_ID_SUFFIX);
- if (node) {
- node.parentNode.removeChild(node);
- }
- }
- return rendered;
- },
-
- /**
- * Method: redrawNode
- *
- * Parameters:
- * id - {String}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the complete geometry could be drawn, null if parts of
- * the geometry could not be drawn, false otherwise
- */
- redrawNode: function(id, geometry, style, featureId) {
- style = this.applyDefaultSymbolizer(style);
- // Get the node if it's already on the map.
- var node = this.nodeFactory(id, this.getNodeType(geometry, style));
-
- // Set the data for the node, then draw it.
- node._featureId = featureId;
- node._boundsBottom = geometry.getBounds().bottom;
- node._geometryClass = geometry.CLASS_NAME;
- node._style = style;
-
- var drawResult = this.drawGeometryNode(node, geometry, style);
- if(drawResult === false) {
- return false;
- }
-
- node = drawResult.node;
-
- // Insert the node into the indexer so it can show us where to
- // place it. Note that this operation is O(log(n)). If there's a
- // performance problem (when dragging, for instance) this is
- // likely where it would be.
- if (this.indexer) {
- var insert = this.indexer.insert(node);
- if (insert) {
- this.vectorRoot.insertBefore(node, insert);
- } else {
- this.vectorRoot.appendChild(node);
- }
- } else {
- // if there's no indexer, simply append the node to root,
- // but only if the node is a new one
- if (node.parentNode !== this.vectorRoot){
- this.vectorRoot.appendChild(node);
- }
- }
-
- this.postDraw(node);
-
- return drawResult.complete;
- },
-
- /**
- * Method: redrawBackgroundNode
- * Redraws the node using special 'background' style properties. Basically
- * just calls redrawNode(), but instead of directly using the
- * 'externalGraphic', 'graphicXOffset', 'graphicYOffset', and
- * 'graphicZIndex' properties directly from the specified 'style'
- * parameter, we create a new style object and set those properties
- * from the corresponding 'background'-prefixed properties from
- * specified 'style' parameter.
- *
- * Parameters:
- * id - {String}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- * featureId - {String}
- *
- * Returns:
- * {Boolean} true if the complete geometry could be drawn, null if parts of
- * the geometry could not be drawn, false otherwise
- */
- redrawBackgroundNode: function(id, geometry, style, featureId) {
- var backgroundStyle = OpenLayers.Util.extend({}, style);
-
- // Set regular style attributes to apply to the background styles.
- backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic;
- backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset;
- backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset;
- backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex;
- backgroundStyle.graphicWidth = backgroundStyle.backgroundWidth || backgroundStyle.graphicWidth;
- backgroundStyle.graphicHeight = backgroundStyle.backgroundHeight || backgroundStyle.graphicHeight;
-
- // Erase background styles.
- backgroundStyle.backgroundGraphic = null;
- backgroundStyle.backgroundXOffset = null;
- backgroundStyle.backgroundYOffset = null;
- backgroundStyle.backgroundGraphicZIndex = null;
-
- return this.redrawNode(
- id + this.BACKGROUND_ID_SUFFIX,
- geometry,
- backgroundStyle,
- null
- );
- },
-
- /**
- * Method: drawGeometryNode
- * Given a node, draw a geometry on the specified layer.
- * node and geometry are required arguments, style is optional.
- * This method is only called by the render itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {Object} a hash with properties "node" (the drawn node) and "complete"
- * (null if parts of the geometry could not be drawn, false if nothing
- * could be drawn)
- */
- drawGeometryNode: function(node, geometry, style) {
- style = style || node._style;
-
- var options = {
- 'isFilled': style.fill === undefined ?
- true :
- style.fill,
- 'isStroked': style.stroke === undefined ?
- !!style.strokeWidth :
- style.stroke
- };
- var drawn;
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- if(style.graphic === false) {
- options.isFilled = false;
- options.isStroked = false;
- }
- drawn = this.drawPoint(node, geometry);
- break;
- case "OpenLayers.Geometry.LineString":
- options.isFilled = false;
- drawn = this.drawLineString(node, geometry);
- break;
- case "OpenLayers.Geometry.LinearRing":
- drawn = this.drawLinearRing(node, geometry);
- break;
- case "OpenLayers.Geometry.Polygon":
- drawn = this.drawPolygon(node, geometry);
- break;
- case "OpenLayers.Geometry.Rectangle":
- drawn = this.drawRectangle(node, geometry);
- break;
- default:
- break;
- }
-
- node._options = options;
-
- //set style
- //TBD simplify this
- if (drawn != false) {
- return {
- node: this.setStyle(node, style, options, geometry),
- complete: drawn
- };
- } else {
- return false;
- }
- },
-
- /**
- * Method: postDraw
- * Things that have do be done after the geometry node is appended
- * to its parent node. To be overridden by subclasses.
- *
- * Parameters:
- * node - {DOMElement}
- */
- postDraw: function(node) {},
-
- /**
- * Method: drawPoint
- * Virtual function for drawing Point Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the point
- */
- drawPoint: function(node, geometry) {},
-
- /**
- * Method: drawLineString
- * Virtual function for drawing LineString Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components of
- * the linestring, or false if nothing could be drawn
- */
- drawLineString: function(node, geometry) {},
-
- /**
- * Method: drawLinearRing
- * Virtual function for drawing LinearRing Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the linear ring, or false if nothing could be drawn
- */
- drawLinearRing: function(node, geometry) {},
-
- /**
- * Method: drawPolygon
- * Virtual function for drawing Polygon Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the polygon, or false if nothing could be drawn
- */
- drawPolygon: function(node, geometry) {},
-
- /**
- * Method: drawRectangle
- * Virtual function for drawing Rectangle Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the rectangle
- */
- drawRectangle: function(node, geometry) {},
-
- /**
- * Method: drawCircle
- * Virtual function for drawing Circle Geometry.
- * Should be implemented by subclasses.
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the circle
- */
- drawCircle: function(node, geometry) {},
-
- /**
- * Method: removeText
- * Removes a label
- *
- * Parameters:
- * featureId - {String}
- */
- removeText: function(featureId) {
- var label = document.getElementById(featureId + this.LABEL_ID_SUFFIX);
- if (label) {
- this.textRoot.removeChild(label);
- }
- var outline = document.getElementById(featureId + this.LABEL_OUTLINE_SUFFIX);
- if (outline) {
- this.textRoot.removeChild(outline);
- }
- },
-
- /**
- * Method: getFeatureIdFromEvent
- *
- * Parameters:
- * evt - {Object} An <OpenLayers.Event> object
- *
- * Returns:
- * {String} A feature id or undefined.
- */
- getFeatureIdFromEvent: function(evt) {
- var target = evt.target;
- var useElement = target && target.correspondingUseElement;
- var node = useElement ? useElement : (target || evt.srcElement);
- return node._featureId;
- },
-
- /**
- * Method: eraseGeometry
- * Erase a geometry from the renderer. In the case of a multi-geometry,
- * we cycle through and recurse on ourselves. Otherwise, we look for a
- * node with the geometry.id, destroy its geometry, and remove it from
- * the DOM.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * featureId - {String}
- */
- eraseGeometry: function(geometry, featureId) {
- if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon") ||
- (geometry.CLASS_NAME == "OpenLayers.Geometry.Collection")) {
- for (var i=0, len=geometry.components.length; i<len; i++) {
- this.eraseGeometry(geometry.components[i], featureId);
- }
- } else {
- var element = OpenLayers.Util.getElement(geometry.id);
- if (element && element.parentNode) {
- if (element.geometry) {
- element.geometry.destroy();
- element.geometry = null;
- }
- element.parentNode.removeChild(element);
-
- if (this.indexer) {
- this.indexer.remove(element);
- }
-
- if (element._style.backgroundGraphic) {
- var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
- var bElem = OpenLayers.Util.getElement(backgroundId);
- if (bElem && bElem.parentNode) {
- // No need to destroy the geometry since the element and the background
- // node share the same geometry.
- bElem.parentNode.removeChild(bElem);
- }
- }
- }
- }
- },
-
- /**
- * Method: nodeFactory
- * Create new node of the specified type, with the (optional) specified id.
- *
- * If node already exists with same ID and a different type, we remove it
- * and then call ourselves again to recreate it.
- *
- * Parameters:
- * id - {String}
- * type - {String} type Kind of node to draw.
- *
- * Returns:
- * {DOMElement} A new node of the given type and id.
- */
- nodeFactory: function(id, type) {
- var node = OpenLayers.Util.getElement(id);
- if (node) {
- if (!this.nodeTypeCompare(node, type)) {
- node.parentNode.removeChild(node);
- node = this.nodeFactory(id, type);
- }
- } else {
- node = this.createNode(type, id);
- }
- return node;
- },
-
- /**
- * Method: nodeTypeCompare
- *
- * Parameters:
- * node - {DOMElement}
- * type - {String} Kind of node
- *
- * Returns:
- * {Boolean} Whether or not the specified node is of the specified type
- * This function must be overridden by subclasses.
- */
- nodeTypeCompare: function(node, type) {},
-
- /**
- * Method: createNode
- *
- * Parameters:
- * type - {String} Kind of node to draw.
- * id - {String} Id for node.
- *
- * Returns:
- * {DOMElement} A new node of the given type and id.
- * This function must be overridden by subclasses.
- */
- createNode: function(type, id) {},
-
- /**
- * Method: moveRoot
- * moves this renderer's root to a different renderer.
- *
- * Parameters:
- * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
- */
- moveRoot: function(renderer) {
- var root = this.root;
- if(renderer.root.parentNode == this.rendererRoot) {
- root = renderer.root;
- }
- root.parentNode.removeChild(root);
- renderer.rendererRoot.appendChild(root);
- },
-
- /**
- * Method: getRenderLayerId
- * Gets the layer that this renderer's output appears on. If moveRoot was
- * used, this will be different from the id of the layer containing the
- * features rendered by this renderer.
- *
- * Returns:
- * {String} the id of the output layer.
- */
- getRenderLayerId: function() {
- return this.root.parentNode.parentNode.id;
- },
-
- /**
- * Method: isComplexSymbol
- * Determines if a symbol cannot be rendered using drawCircle
- *
- * Parameters:
- * graphicName - {String}
- *
- * Returns
- * {Boolean} true if the symbol is complex, false if not
- */
- isComplexSymbol: function(graphicName) {
- return (graphicName != "circle") && !!graphicName;
- },
-
- CLASS_NAME: "OpenLayers.Renderer.Elements"
-});
-
-/* ======================================================================
- OpenLayers/Control/Panel.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Events/buttonclick.js
- */
-
-/**
- * Class: OpenLayers.Control.Panel
- * The Panel control is a container for other controls. With it toolbars
- * may be composed.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, {
- /**
- * Property: controls
- * {Array(<OpenLayers.Control>)}
- */
- controls: null,
-
- /**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * true.
- */
- autoActivate: true,
-
- /**
- * APIProperty: defaultControl
- * {<OpenLayers.Control>} The control which is activated when the control is
- * activated (turned on), which also happens at instantiation.
- * If <saveState> is true, <defaultControl> will be nullified after the
- * first activation of the panel.
- */
- defaultControl: null,
-
- /**
- * APIProperty: saveState
- * {Boolean} If set to true, the active state of this panel's controls will
- * be stored on panel deactivation, and restored on reactivation. Default
- * is false.
- */
- saveState: false,
-
- /**
- * APIProperty: allowDepress
- * {Boolean} If is true the <OpenLayers.Control.TYPE_TOOL> controls can
- * be deactivated by clicking the icon that represents them. Default
- * is false.
- */
- allowDepress: false,
-
- /**
- * Property: activeState
- * {Object} stores the active state of this panel's controls.
- */
- activeState: null,
-
- /**
- * Constructor: OpenLayers.Control.Panel
- * Create a new control panel.
- *
- * Each control in the panel is represented by an icon. When clicking
- * on an icon, the <activateControl> method is called.
- *
- * Specific properties for controls on a panel:
- * type - {Number} One of <OpenLayers.Control.TYPE_TOOL>,
- * <OpenLayers.Control.TYPE_TOGGLE>, <OpenLayers.Control.TYPE_BUTTON>.
- * If not provided, <OpenLayers.Control.TYPE_TOOL> is assumed.
- * title - {string} Text displayed when mouse is over the icon that
- * represents the control.
- *
- * The <OpenLayers.Control.type> of a control determines the behavior when
- * clicking its icon:
- * <OpenLayers.Control.TYPE_TOOL> - The control is activated and other
- * controls of this type in the same panel are deactivated. This is
- * the default type.
- * <OpenLayers.Control.TYPE_TOGGLE> - The active state of the control is
- * toggled.
- * <OpenLayers.Control.TYPE_BUTTON> - The
- * <OpenLayers.Control.Button.trigger> method of the control is called,
- * but its active state is not changed.
- *
- * If a control is <OpenLayers.Control.active>, it will be drawn with the
- * olControl[Name]ItemActive class, otherwise with the
- * olControl[Name]ItemInactive class.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be used
- * to extend the control.
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- this.controls = [];
- this.activeState = {};
- },
-
- /**
- * APIMethod: destroy
- */
- destroy: function() {
- if (this.map) {
- this.map.events.unregister("buttonclick", this, this.onButtonClick);
- }
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- for (var ctl, i = this.controls.length - 1; i >= 0; i--) {
- ctl = this.controls[i];
- if (ctl.events) {
- ctl.events.un({
- activate: this.iconOn,
- deactivate: this.iconOff
- });
- }
- ctl.panel_div = null;
- }
- this.activeState = null;
- },
-
- /**
- * APIMethod: activate
- */
- activate: function() {
- if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
- var control;
- for (var i=0, len=this.controls.length; i<len; i++) {
- control = this.controls[i];
- if (control === this.defaultControl ||
- (this.saveState && this.activeState[control.id])) {
- control.activate();
- }
- }
- if (this.saveState === true) {
- this.defaultControl = null;
- }
- this.redraw();
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * APIMethod: deactivate
- */
- deactivate: function() {
- if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
- var control;
- for (var i=0, len=this.controls.length; i<len; i++) {
- control = this.controls[i];
- this.activeState[control.id] = control.deactivate();
- }
- this.redraw();
- return true;
- } else {
- return false;
- }
- },
-
- /**
- * Method: draw
- *
- * Returns:
- * {DOMElement}
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
- if (this.outsideViewport) {
- this.events.attachToElement(this.div);
- this.events.register("buttonclick", this, this.onButtonClick);
- } else {
- this.map.events.register("buttonclick", this, this.onButtonClick);
- }
- this.addControlsToMap(this.controls);
- return this.div;
- },
-
- /**
- * Method: redraw
- */
- redraw: function() {
- for (var l=this.div.childNodes.length, i=l-1; i>=0; i--) {
- this.div.removeChild(this.div.childNodes[i]);
- }
- this.div.innerHTML = "";
- if (this.active) {
- for (var i=0, len=this.controls.length; i<len; i++) {
- this.div.appendChild(this.controls[i].panel_div);
- }
- }
- },
-
- /**
- * APIMethod: activateControl
- * This method is called when the user click on the icon representing a
- * control in the panel.
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- */
- activateControl: function (control) {
- if (!this.active) { return false; }
- if (control.type == OpenLayers.Control.TYPE_BUTTON) {
- control.trigger();
- return;
- }
- if (control.type == OpenLayers.Control.TYPE_TOGGLE) {
- if (control.active) {
- control.deactivate();
- } else {
- control.activate();
- }
- return;
- }
- if (this.allowDepress && control.active) {
- control.deactivate();
- } else {
- var c;
- for (var i=0, len=this.controls.length; i<len; i++) {
- c = this.controls[i];
- if (c != control &&
- (c.type === OpenLayers.Control.TYPE_TOOL || c.type == null)) {
- c.deactivate();
- }
- }
- control.activate();
- }
- },
-
- /**
- * APIMethod: addControls
- * To build a toolbar, you add a set of controls to it. addControls
- * lets you add a single control or a list of controls to the
- * Control Panel.
- *
- * Parameters:
- * controls - {<OpenLayers.Control>} Controls to add in the panel.
- */
- addControls: function(controls) {
- if (!(OpenLayers.Util.isArray(controls))) {
- controls = [controls];
- }
- this.controls = this.controls.concat(controls);
-
- for (var i=0, len=controls.length; i<len; i++) {
- var control = controls[i],
- element = this.createControlMarkup(control);
- OpenLayers.Element.addClass(element,
- control.displayClass + "ItemInactive");
- OpenLayers.Element.addClass(element, "olButton");
- if (control.title != "" && !element.title) {
- element.title = control.title;
- }
- control.panel_div = element;
- }
-
- if (this.map) { // map.addControl() has already been called on the panel
- this.addControlsToMap(controls);
- this.redraw();
- }
- },
-
- /**
- * APIMethod: createControlMarkup
- * This function just creates a div for the control. If specific HTML
- * markup is needed this function can be overridden in specific classes,
- * or at panel instantiation time:
- *
- * Example:
- * (code)
- * var panel = new OpenLayers.Control.Panel({
- * defaultControl: control,
- * // ovverride createControlMarkup to create actual buttons
- * // including texts wrapped into span elements.
- * createControlMarkup: function(control) {
- * var button = document.createElement('button'),
- * span = document.createElement('span');
- * if (control.text) {
- * span.innerHTML = control.text;
- * }
- * return button;
- * }
- * });
- * (end)
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control to create the HTML
- * markup for.
- *
- * Returns:
- * {DOMElement} The markup.
- */
- createControlMarkup: function(control) {
- return document.createElement("div");
- },
-
- /**
- * Method: addControlsToMap
- * Only for internal use in draw() and addControls() methods.
- *
- * Parameters:
- * controls - {Array(<OpenLayers.Control>)} Controls to add into map.
- */
- addControlsToMap: function (controls) {
- var control;
- for (var i=0, len=controls.length; i<len; i++) {
- control = controls[i];
- if (control.autoActivate === true) {
- control.autoActivate = false;
- this.map.addControl(control);
- control.autoActivate = true;
- } else {
- this.map.addControl(control);
- control.deactivate();
- }
- control.events.on({
- activate: this.iconOn,
- deactivate: this.iconOff
- });
- }
- },
-
- /**
- * Method: iconOn
- * Internal use, for use only with "controls[i].events.on/un".
- */
- iconOn: function() {
- var d = this.panel_div; // "this" refers to a control on panel!
- var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b");
- d.className = d.className.replace(re, "$1Active");
- },
-
- /**
- * Method: iconOff
- * Internal use, for use only with "controls[i].events.on/un".
- */
- iconOff: function() {
- var d = this.panel_div; // "this" refers to a control on panel!
- var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b");
- d.className = d.className.replace(re, "$1Inactive");
- },
-
- /**
- * Method: onButtonClick
- *
- * Parameters:
- * evt - {Event}
- */
- onButtonClick: function (evt) {
- var controls = this.controls,
- button = evt.buttonElement;
- for (var i=controls.length-1; i>=0; --i) {
- if (controls[i].panel_div === button) {
- this.activateControl(controls[i]);
- break;
- }
- }
- },
-
- /**
- * 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(control[property]) evaluates to true, the control will be
- * included in the array returned. If no controls 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) {
- var test = (typeof match.test == "function");
- var found = OpenLayers.Array.filter(this.controls, function(item) {
- return item[property] == match || (test && match.test(item[property]));
- });
- return found;
- },
-
- /**
- * APIMethod: getControlsByName
- * Get a list of contorls with names matching the given name.
- *
- * Parameters:
- * match - {String | Object} A control 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(control.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 name.
- * An empty array is returned if no matches are found.
- */
- getControlsByName: function(match) {
- return this.getControlsBy("name", match);
- },
-
- /**
- * APIMethod: getControlsByClass
- * Get a list of controls of a given type (CLASS_NAME).
- *
- * Parameters:
- * match - {String | Object} A control class name. The type 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 type.
- * An empty array is returned if no matches are found.
- */
- getControlsByClass: function(match) {
- return this.getControlsBy("CLASS_NAME", match);
- },
-
- CLASS_NAME: "OpenLayers.Control.Panel"
-});
-
-/* ======================================================================
- OpenLayers/Strategy.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- */
-
-/**
- * Class: OpenLayers.Strategy
- * Abstract vector layer strategy class. Not to be instantiated directly. Use
- * one of the strategy subclasses instead.
- */
-OpenLayers.Strategy = OpenLayers.Class({
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
- */
- layer: null,
-
- /**
- * Property: options
- * {Object} Any options sent to the constructor.
- */
- options: null,
-
- /**
- * Property: active
- * {Boolean} The control is active.
- */
- active: null,
-
- /**
- * Property: autoActivate
- * {Boolean} The creator of the strategy can set autoActivate to false
- * to fully control when the protocol is activated and deactivated.
- * Defaults to true.
- */
- autoActivate: true,
-
- /**
- * Property: autoDestroy
- * {Boolean} The creator of the strategy can set autoDestroy to false
- * to fully control when the strategy is destroyed. Defaults to
- * true.
- */
- autoDestroy: true,
-
- /**
- * Constructor: OpenLayers.Strategy
- * Abstract class for vector strategies. Create instances of a subclass.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- this.options = options;
- // set the active property here, so that user cannot override it
- this.active = false;
- },
-
- /**
- * APIMethod: destroy
- * Clean up the strategy.
- */
- destroy: function() {
- this.deactivate();
- this.layer = null;
- this.options = null;
- },
-
- /**
- * Method: setLayer
- * Called to set the <layer> property.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer.Vector>}
- */
- setLayer: function(layer) {
- this.layer = layer;
- },
-
- /**
- * Method: activate
- * Activate the strategy. Register any listeners, do appropriate setup.
- *
- * Returns:
- * {Boolean} True if the strategy was successfully activated or false if
- * the strategy was already active.
- */
- activate: function() {
- if (!this.active) {
- this.active = true;
- return true;
- }
- return false;
- },
-
- /**
- * Method: deactivate
- * Deactivate the strategy. Unregister any listeners, do appropriate
- * tear-down.
- *
- * Returns:
- * {Boolean} True if the strategy was successfully deactivated or false if
- * the strategy was already inactive.
- */
- deactivate: function() {
- if (this.active) {
- this.active = false;
- return true;
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Strategy"
-});
-/* ======================================================================
- OpenLayers/Strategy/Fixed.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Strategy.js
- */
-
-/**
- * Class: OpenLayers.Strategy.Fixed
- * A simple strategy that requests features once and never requests new data.
- *
- * Inherits from:
- * - <OpenLayers.Strategy>
- */
-OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
-
- /**
- * APIProperty: preload
- * {Boolean} Load data before layer made visible. Enabling this may result
- * in considerable overhead if your application loads many data layers
- * that are not visible by default. Default is false.
- */
- preload: false,
-
- /**
- * Constructor: OpenLayers.Strategy.Fixed
- * Create a new Fixed strategy.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
-
- /**
- * Method: activate
- * Activate the strategy: load data or add listener to load when visible
- *
- * Returns:
- * {Boolean} True if the strategy was successfully activated or false if
- * the strategy was already active.
- */
- activate: function() {
- var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);
- if(activated) {
- this.layer.events.on({
- "refresh": this.load,
- scope: this
- });
- if(this.layer.visibility == true || this.preload) {
- this.load();
- } else {
- this.layer.events.on({
- "visibilitychanged": this.load,
- scope: this
- });
- }
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Deactivate the strategy. Undo what is done in <activate>.
- *
- * Returns:
- * {Boolean} The strategy was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
- if(deactivated) {
- this.layer.events.un({
- "refresh": this.load,
- "visibilitychanged": this.load,
- scope: this
- });
- }
- return deactivated;
- },
-
- /**
- * Method: load
- * Tells protocol to load data and unhooks the visibilitychanged event
- *
- * Parameters:
- * options - {Object} options to pass to protocol read.
- */
- load: function(options) {
- var layer = this.layer;
- layer.events.triggerEvent("loadstart", {filter: layer.filter});
- layer.protocol.read(OpenLayers.Util.applyDefaults({
- callback: this.merge,
- filter: layer.filter,
- scope: this
- }, options));
- layer.events.un({
- "visibilitychanged": this.load,
- scope: this
- });
- },
-
- /**
- * Method: merge
- * Add all features to the layer.
- * If the layer projection differs from the map projection, features
- * will be transformed from the layer projection to the map projection.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object passed
- * by the protocol.
- */
- merge: function(resp) {
- var layer = this.layer;
- layer.destroyFeatures();
- var features = resp.features;
- if (features && features.length > 0) {
- var remote = layer.projection;
- var local = layer.map.getProjectionObject();
- if(!local.equals(remote)) {
- var geom;
- for(var i=0, len=features.length; i<len; ++i) {
- geom = features[i].geometry;
- if(geom) {
- geom.transform(remote, local);
- }
- }
- }
- layer.addFeatures(features);
- }
- layer.events.triggerEvent("loadend", {response: resp});
- },
-
- CLASS_NAME: "OpenLayers.Strategy.Fixed"
-});
-/* ======================================================================
- OpenLayers/Control/Zoom.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Events/buttonclick.js
- */
-
-/**
- * Class: OpenLayers.Control.Zoom
- * The Zoom control is a pair of +/- links for zooming in and out.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * APIProperty: zoomInText
- * {String}
- * Text for zoom-in link. Default is "+".
- */
- zoomInText: "+",
-
- /**
- * APIProperty: zoomInId
- * {String}
- * Instead of having the control create a zoom in link, you can provide
- * the identifier for an anchor element already added to the document.
- * By default, an element with id "olZoomInLink" will be searched for
- * and used if it exists.
- */
- zoomInId: "olZoomInLink",
-
- /**
- * APIProperty: zoomOutText
- * {String}
- * Text for zoom-out link. Default is "\u2212".
- */
- zoomOutText: "\u2212",
-
- /**
- * APIProperty: zoomOutId
- * {String}
- * Instead of having the control create a zoom out link, you can provide
- * the identifier for an anchor element already added to the document.
- * By default, an element with id "olZoomOutLink" will be searched for
- * and used if it exists.
- */
- zoomOutId: "olZoomOutLink",
-
- /**
- * Method: draw
- *
- * Returns:
- * {DOMElement} A reference to the DOMElement containing the zoom links.
- */
- draw: function() {
- var div = OpenLayers.Control.prototype.draw.apply(this),
- links = this.getOrCreateLinks(div),
- zoomIn = links.zoomIn,
- zoomOut = links.zoomOut,
- eventsInstance = this.map.events;
-
- if (zoomOut.parentNode !== div) {
- eventsInstance = this.events;
- eventsInstance.attachToElement(zoomOut.parentNode);
- }
- eventsInstance.register("buttonclick", this, this.onZoomClick);
-
- this.zoomInLink = zoomIn;
- this.zoomOutLink = zoomOut;
- return div;
- },
-
- /**
- * Method: getOrCreateLinks
- *
- * Parameters:
- * el - {DOMElement}
- *
- * Return:
- * {Object} Object with zoomIn and zoomOut properties referencing links.
- */
- getOrCreateLinks: function(el) {
- var zoomIn = document.getElementById(this.zoomInId),
- zoomOut = document.getElementById(this.zoomOutId);
- if (!zoomIn) {
- zoomIn = document.createElement("a");
- zoomIn.href = "#zoomIn";
- zoomIn.appendChild(document.createTextNode(this.zoomInText));
- zoomIn.className = "olControlZoomIn";
- el.appendChild(zoomIn);
- }
- OpenLayers.Element.addClass(zoomIn, "olButton");
- if (!zoomOut) {
- zoomOut = document.createElement("a");
- zoomOut.href = "#zoomOut";
- zoomOut.appendChild(document.createTextNode(this.zoomOutText));
- zoomOut.className = "olControlZoomOut";
- el.appendChild(zoomOut);
- }
- OpenLayers.Element.addClass(zoomOut, "olButton");
- return {
- zoomIn: zoomIn, zoomOut: zoomOut
- };
- },
-
- /**
- * Method: onZoomClick
- * Called when zoomin/out link is clicked.
- */
- onZoomClick: function(evt) {
- var button = evt.buttonElement;
- if (button === this.zoomInLink) {
- this.map.zoomIn();
- } else if (button === this.zoomOutLink) {
- this.map.zoomOut();
- }
- },
-
- /**
- * Method: destroy
- * Clean up.
- */
- destroy: function() {
- if (this.map) {
- this.map.events.unregister("buttonclick", this, this.onZoomClick);
- }
- delete this.zoomInLink;
- delete this.zoomOutLink;
- OpenLayers.Control.prototype.destroy.apply(this);
- },
-
- CLASS_NAME: "OpenLayers.Control.Zoom"
-});
-/* ======================================================================
- OpenLayers/Protocol.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- */
-
-/**
- * Class: OpenLayers.Protocol
- * Abstract vector layer protocol class. Not to be instantiated directly. Use
- * one of the protocol subclasses instead.
- */
-OpenLayers.Protocol = OpenLayers.Class({
-
- /**
- * Property: format
- * {<OpenLayers.Format>} The format used by this protocol.
- */
- format: null,
-
- /**
- * Property: options
- * {Object} Any options sent to the constructor.
- */
- options: null,
-
- /**
- * Property: autoDestroy
- * {Boolean} The creator of the protocol can set autoDestroy to false
- * to fully control when the protocol is destroyed. Defaults to
- * true.
- */
- autoDestroy: true,
-
- /**
- * Property: defaultFilter
- * {<OpenLayers.Filter>} Optional default filter to read requests
- */
- defaultFilter: null,
-
- /**
- * Constructor: OpenLayers.Protocol
- * Abstract class for vector protocols. Create instances of a subclass.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- options = options || {};
- OpenLayers.Util.extend(this, options);
- this.options = options;
- },
-
- /**
- * Method: mergeWithDefaultFilter
- * Merge filter passed to the read method with the default one
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>}
- */
- mergeWithDefaultFilter: function(filter) {
- var merged;
- if (filter && this.defaultFilter) {
- merged = new OpenLayers.Filter.Logical({
- type: OpenLayers.Filter.Logical.AND,
- filters: [this.defaultFilter, filter]
- });
- } else {
- merged = filter || this.defaultFilter || undefined;
- }
- return merged;
- },
-
- /**
- * APIMethod: destroy
- * Clean up the protocol.
- */
- destroy: function() {
- this.options = null;
- this.format = null;
- },
-
- /**
- * APIMethod: read
- * Construct a request for reading new features.
- *
- * Parameters:
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- read: function(options) {
- options = options || {};
- options.filter = this.mergeWithDefaultFilter(options.filter);
- },
-
-
- /**
- * APIMethod: create
- * Construct a request for writing newly created features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- create: function() {
- },
-
- /**
- * APIMethod: update
- * Construct a request updating modified features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- update: function() {
- },
-
- /**
- * APIMethod: delete
- * Construct a request deleting a removed feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, the same object will be passed to the callback function passed
- * if one exists in the options object.
- */
- "delete": function() {
- },
-
- /**
- * APIMethod: commit
- * Go over the features and for each take action
- * based on the feature state. Possible actions are create,
- * update and delete.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})}
- * options - {Object} Object whose possible keys are "create", "update",
- * "delete", "callback" and "scope", the values referenced by the
- * first three are objects as passed to the "create", "update", and
- * "delete" methods, the value referenced by the "callback" key is
- * a function which is called when the commit operation is complete
- * using the scope referenced by the "scope" key.
- *
- * Returns:
- * {Array({<OpenLayers.Protocol.Response>})} An array of
- * <OpenLayers.Protocol.Response> objects.
- */
- commit: function() {
- },
-
- /**
- * Method: abort
- * Abort an ongoing request.
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>}
- */
- abort: function(response) {
- },
-
- /**
- * Method: createCallback
- * Returns a function that applies the given public method with resp and
- * options arguments.
- *
- * Parameters:
- * method - {Function} The method to be applied by the callback.
- * response - {<OpenLayers.Protocol.Response>} The protocol response object.
- * options - {Object} Options sent to the protocol method
- */
- createCallback: function(method, response, options) {
- return OpenLayers.Function.bind(function() {
- method.apply(this, [response, options]);
- }, this);
- },
-
- CLASS_NAME: "OpenLayers.Protocol"
-});
-
-/**
- * Class: OpenLayers.Protocol.Response
- * Protocols return Response objects to their users.
- */
-OpenLayers.Protocol.Response = OpenLayers.Class({
- /**
- * Property: code
- * {Number} - OpenLayers.Protocol.Response.SUCCESS or
- * OpenLayers.Protocol.Response.FAILURE
- */
- code: null,
-
- /**
- * Property: requestType
- * {String} The type of request this response corresponds to. Either
- * "create", "read", "update" or "delete".
- */
- requestType: null,
-
- /**
- * Property: last
- * {Boolean} - true if this is the last response expected in a commit,
- * false otherwise, defaults to true.
- */
- last: true,
-
- /**
- * Property: features
- * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
- * The features returned in the response by the server. Depending on the
- * protocol's read payload, either features or data will be populated.
- */
- features: null,
-
- /**
- * Property: data
- * {Object}
- * The data returned in the response by the server. Depending on the
- * protocol's read payload, either features or data will be populated.
- */
- data: null,
-
- /**
- * Property: reqFeatures
- * {Array({<OpenLayers.Feature.Vector>})} or {<OpenLayers.Feature.Vector>}
- * The features provided by the user and placed in the request by the
- * protocol.
- */
- reqFeatures: null,
-
- /**
- * Property: priv
- */
- priv: null,
-
- /**
- * Property: error
- * {Object} The error object in case a service exception was encountered.
- */
- error: null,
-
- /**
- * Constructor: OpenLayers.Protocol.Response
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * Method: success
- *
- * Returns:
- * {Boolean} - true on success, false otherwise
- */
- success: function() {
- return this.code > 0;
- },
-
- CLASS_NAME: "OpenLayers.Protocol.Response"
-});
-
-OpenLayers.Protocol.Response.SUCCESS = 1;
-OpenLayers.Protocol.Response.FAILURE = 0;
-/* ======================================================================
- OpenLayers/Protocol/WFS.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Protocol.js
- */
-
-/**
- * Class: OpenLayers.Protocol.WFS
- * Used to create a versioned WFS protocol. Default version is 1.0.0.
- *
- * Returns:
- * {<OpenLayers.Protocol>} A WFS protocol of the given version.
- *
- * Example:
- * (code)
- * var protocol = new OpenLayers.Protocol.WFS({
- * version: "1.1.0",
- * url: "http://demo.opengeo.org/geoserver/wfs",
- * featureType: "tasmania_roads",
- * featureNS: "http://www.openplans.org/topp",
- * geometryName: "the_geom"
- * });
- * (end)
- *
- * See the protocols for specific WFS versions for more detail.
- */
-OpenLayers.Protocol.WFS = function(options) {
- options = OpenLayers.Util.applyDefaults(
- options, OpenLayers.Protocol.WFS.DEFAULTS
- );
- var cls = OpenLayers.Protocol.WFS["v"+options.version.replace(/\./g, "_")];
- if(!cls) {
- throw "Unsupported WFS version: " + options.version;
- }
- return new cls(options);
-};
-
-/**
- * Function: fromWMSLayer
- * Convenience function to create a WFS protocol from a WMS layer. This makes
- * the assumption that a WFS requests can be issued at the same URL as
- * WMS requests and that a WFS featureType exists with the same name as the
- * WMS layer.
- *
- * This function is designed to auto-configure <url>, <featureType>,
- * <featurePrefix> and <srsName> for WFS <version> 1.1.0. Note that
- * srsName matching with the WMS layer will not work with WFS 1.0.0.
- *
- * Parameters:
- * layer - {<OpenLayers.Layer.WMS>} WMS layer that has a matching WFS
- * FeatureType at the same server url with the same typename.
- * options - {Object} Default properties to be set on the protocol.
- *
- * Returns:
- * {<OpenLayers.Protocol.WFS>}
- */
-OpenLayers.Protocol.WFS.fromWMSLayer = function(layer, options) {
- var typeName, featurePrefix;
- var param = layer.params["LAYERS"];
- var parts = (OpenLayers.Util.isArray(param) ? param[0] : param).split(":");
- if(parts.length > 1) {
- featurePrefix = parts[0];
- }
- typeName = parts.pop();
- var protocolOptions = {
- url: layer.url,
- featureType: typeName,
- featurePrefix: featurePrefix,
- srsName: layer.projection && layer.projection.getCode() ||
- layer.map && layer.map.getProjectionObject().getCode(),
- version: "1.1.0"
- };
- return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(
- options, protocolOptions
- ));
-};
-
-/**
- * Constant: OpenLayers.Protocol.WFS.DEFAULTS
- */
-OpenLayers.Protocol.WFS.DEFAULTS = {
- "version": "1.0.0"
-};
-/* ======================================================================
- OpenLayers/Request.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Events.js
- * @requires OpenLayers/Request/XMLHttpRequest.js
- */
-
-/**
- * TODO: deprecate me
- * Use OpenLayers.Request.proxy instead.
- */
-OpenLayers.ProxyHost = "";
-
-/**
- * Namespace: OpenLayers.Request
- * The OpenLayers.Request namespace contains convenience methods for working
- * with XMLHttpRequests. These methods work with a cross-browser
- * W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
- */
-if (!OpenLayers.Request) {
- /**
- * This allows for OpenLayers/Request/XMLHttpRequest.js to be included
- * before or after this script.
- */
- OpenLayers.Request = {};
-}
-OpenLayers.Util.extend(OpenLayers.Request, {
-
- /**
- * Constant: DEFAULT_CONFIG
- * {Object} Default configuration for all requests.
- */
- DEFAULT_CONFIG: {
- method: "GET",
- url: window.location.href,
- async: true,
- user: undefined,
- password: undefined,
- params: null,
- proxy: OpenLayers.ProxyHost,
- headers: {},
- data: null,
- callback: function() {},
- success: null,
- failure: null,
- scope: null
- },
-
- /**
- * Constant: URL_SPLIT_REGEX
- */
- URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
-
- /**
- * APIProperty: events
- * {<OpenLayers.Events>} An events object that handles all
- * events on the {<OpenLayers.Request>} object.
- *
- * All event listeners will receive an event object with three properties:
- * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
- * config - {Object} The config object sent to the specific request method.
- * requestUrl - {String} The request url.
- *
- * Supported event types:
- * complete - Triggered when we have a response from the request, if a
- * listener returns false, no further response processing will take
- * place.
- * success - Triggered when the HTTP response has a success code (200-299).
- * failure - Triggered when the HTTP response does not have a success code.
- */
- events: new OpenLayers.Events(this),
-
- /**
- * Method: makeSameOrigin
- * Using the specified proxy, returns a same origin url of the provided url.
- *
- * Parameters:
- * url - {String} An arbitrary url
- * proxy {String|Function} The proxy to use to make the provided url a
- * same origin url.
- *
- * Returns
- * {String} the same origin url. If no proxy is provided, the returned url
- * will be the same as the provided url.
- */
- makeSameOrigin: function(url, proxy) {
- var sameOrigin = url.indexOf("http") !== 0;
- var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
- if (urlParts) {
- var location = window.location;
- sameOrigin =
- urlParts[1] == location.protocol &&
- urlParts[3] == location.hostname;
- var uPort = urlParts[4], lPort = location.port;
- if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
- sameOrigin = sameOrigin && uPort == lPort;
- }
- }
- if (!sameOrigin) {
- if (proxy) {
- if (typeof proxy == "function") {
- url = proxy(url);
- } else {
- url = proxy + encodeURIComponent(url);
- }
- }
- }
- return url;
- },
-
- /**
- * APIMethod: issue
- * Create a new XMLHttpRequest object, open it, set any headers, bind
- * a callback to done state, and send any data. It is recommended that
- * you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
- * This method is only documented to provide detail on the configuration
- * options available to all request methods.
- *
- * Parameters:
- * config - {Object} Object containing properties for configuring the
- * request. Allowed configuration properties are described below.
- * This object is modified and should not be reused.
- *
- * Allowed config properties:
- * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
- * OPTIONS. Default is GET.
- * url - {String} URL for the request.
- * async - {Boolean} Open an asynchronous request. Default is true.
- * user - {String} User for relevant authentication scheme. Set
- * to null to clear current user.
- * password - {String} Password for relevant authentication scheme.
- * Set to null to clear current password.
- * proxy - {String} Optional proxy. Defaults to
- * <OpenLayers.ProxyHost>.
- * params - {Object} Any key:value pairs to be appended to the
- * url as a query string. Assumes url doesn't already include a query
- * string or hash. Typically, this is only appropriate for <GET>
- * requests where the query string will be appended to the url.
- * Parameter values that are arrays will be
- * concatenated with a comma (note that this goes against form-encoding)
- * as is done with <OpenLayers.Util.getParameterString>.
- * headers - {Object} Object with header:value pairs to be set on
- * the request.
- * data - {String | Document} Optional data to send with the request.
- * Typically, this is only used with <POST> and <PUT> requests.
- * Make sure to provide the appropriate "Content-Type" header for your
- * data. For <POST> and <PUT> requests, the content type defaults to
- * "application-xml". If your data is a different content type, or
- * if you are using a different HTTP method, set the "Content-Type"
- * header to match your data type.
- * callback - {Function} Function to call when request is done.
- * To determine if the request failed, check request.status (200
- * indicates success).
- * success - {Function} Optional function to call if request status is in
- * the 200s. This will be called in addition to callback above and
- * would typically only be used as an alternative.
- * failure - {Function} Optional function to call if request status is not
- * in the 200s. This will be called in addition to callback above and
- * would typically only be used as an alternative.
- * scope - {Object} If callback is a public method on some object,
- * set the scope to that object.
- *
- * Returns:
- * {XMLHttpRequest} Request object. To abort the request before a response
- * is received, call abort() on the request object.
- */
- issue: function(config) {
- // apply default config - proxy host may have changed
- var defaultConfig = OpenLayers.Util.extend(
- this.DEFAULT_CONFIG,
- {proxy: OpenLayers.ProxyHost}
- );
- config = config || {};
- config.headers = config.headers || {};
- config = OpenLayers.Util.applyDefaults(config, defaultConfig);
- config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);
- // Always set the "X-Requested-With" header to signal that this request
- // was issued through the XHR-object. Since header keys are case
- // insensitive and we want to allow overriding of the "X-Requested-With"
- // header through the user we cannot use applyDefaults, but have to
- // check manually whether we were called with a "X-Requested-With"
- // header.
- var customRequestedWithHeader = false,
- headerKey;
- for(headerKey in config.headers) {
- if (config.headers.hasOwnProperty( headerKey )) {
- if (headerKey.toLowerCase() === 'x-requested-with') {
- customRequestedWithHeader = true;
- }
- }
- }
- if (customRequestedWithHeader === false) {
- // we did not have a custom "X-Requested-With" header
- config.headers['X-Requested-With'] = 'XMLHttpRequest';
- }
-
- // create request, open, and set headers
- var request = new OpenLayers.Request.XMLHttpRequest();
- var url = OpenLayers.Util.urlAppend(config.url,
- OpenLayers.Util.getParameterString(config.params || {}));
- url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
- request.open(
- config.method, url, config.async, config.user, config.password
- );
- for(var header in config.headers) {
- request.setRequestHeader(header, config.headers[header]);
- }
-
- var events = this.events;
-
- // we want to execute runCallbacks with "this" as the
- // execution scope
- var self = this;
-
- request.onreadystatechange = function() {
- if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
- var proceed = events.triggerEvent(
- "complete",
- {request: request, config: config, requestUrl: url}
- );
- if(proceed !== false) {
- self.runCallbacks(
- {request: request, config: config, requestUrl: url}
- );
- }
- }
- };
-
- // send request (optionally with data) and return
- // call in a timeout for asynchronous requests so the return is
- // available before readyState == 4 for cached docs
- if(config.async === false) {
- request.send(config.data);
- } else {
- window.setTimeout(function(){
- if (request.readyState !== 0) { // W3C: 0-UNSENT
- request.send(config.data);
- }
- }, 0);
- }
- return request;
- },
-
- /**
- * Method: runCallbacks
- * Calls the complete, success and failure callbacks. Application
- * can listen to the "complete" event, have the listener
- * display a confirm window and always return false, and
- * execute OpenLayers.Request.runCallbacks if the user
- * hits "yes" in the confirm window.
- *
- * Parameters:
- * options - {Object} Hash containing request, config and requestUrl keys
- */
- runCallbacks: function(options) {
- var request = options.request;
- var config = options.config;
-
- // bind callbacks to readyState 4 (done)
- var complete = (config.scope) ?
- OpenLayers.Function.bind(config.callback, config.scope) :
- config.callback;
-
- // optional success callback
- var success;
- if(config.success) {
- success = (config.scope) ?
- OpenLayers.Function.bind(config.success, config.scope) :
- config.success;
- }
-
- // optional failure callback
- var failure;
- if(config.failure) {
- failure = (config.scope) ?
- OpenLayers.Function.bind(config.failure, config.scope) :
- config.failure;
- }
-
- if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" &&
- request.responseText) {
- request.status = 200;
- }
- complete(request);
-
- if (!request.status || (request.status >= 200 && request.status < 300)) {
- this.events.triggerEvent("success", options);
- if(success) {
- success(request);
- }
- }
- if(request.status && (request.status < 200 || request.status >= 300)) {
- this.events.triggerEvent("failure", options);
- if(failure) {
- failure(request);
- }
- }
- },
-
- /**
- * APIMethod: GET
- * Send an HTTP GET request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to GET.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- GET: function(config) {
- config = OpenLayers.Util.extend(config, {method: "GET"});
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: POST
- * Send a POST request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to POST and "Content-Type" header set to "application/xml".
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties. The
- * default "Content-Type" header will be set to "application-xml" if
- * none is provided. This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- POST: function(config) {
- config = OpenLayers.Util.extend(config, {method: "POST"});
- // set content type to application/xml if it isn't already set
- config.headers = config.headers ? config.headers : {};
- if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
- config.headers["Content-Type"] = "application/xml";
- }
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: PUT
- * Send an HTTP PUT request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to PUT and "Content-Type" header set to "application/xml".
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties. The
- * default "Content-Type" header will be set to "application-xml" if
- * none is provided. This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- PUT: function(config) {
- config = OpenLayers.Util.extend(config, {method: "PUT"});
- // set content type to application/xml if it isn't already set
- config.headers = config.headers ? config.headers : {};
- if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
- config.headers["Content-Type"] = "application/xml";
- }
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: DELETE
- * Send an HTTP DELETE request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to DELETE.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- DELETE: function(config) {
- config = OpenLayers.Util.extend(config, {method: "DELETE"});
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: HEAD
- * Send an HTTP HEAD request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to HEAD.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- HEAD: function(config) {
- config = OpenLayers.Util.extend(config, {method: "HEAD"});
- return OpenLayers.Request.issue(config);
- },
-
- /**
- * APIMethod: OPTIONS
- * Send an HTTP OPTIONS request. Additional configuration properties are
- * documented in the <issue> method, with the method property set
- * to OPTIONS.
- *
- * Parameters:
- * config - {Object} Object with properties for configuring the request.
- * See the <issue> method for documentation of allowed properties.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {XMLHttpRequest} Request object.
- */
- OPTIONS: function(config) {
- config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
- return OpenLayers.Request.issue(config);
- }
-
-});
-/* ======================================================================
- OpenLayers/Request/XMLHttpRequest.js
- ====================================================================== */
-
-// XMLHttpRequest.js Copyright (C) 2010 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
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/**
- * @requires OpenLayers/Request.js
- */
-
-(function () {
-
- // Save reference to earlier defined object implementation (if any)
- var oXMLHttpRequest = window.XMLHttpRequest;
-
- // Define on browser type
- var bGecko = !!window.controllers,
- bIE = window.document.all && !window.opera,
- bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);
-
- // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()"
- function fXMLHttpRequest() {
- this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
- this._listeners = [];
- };
-
- // Constructor
- function cXMLHttpRequest() {
- return new fXMLHttpRequest;
- };
- cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;
-
- // BUGFIX: Firefox with Firebug installed would break pages if not executed
- if (bGecko && oXMLHttpRequest.wrapped)
- cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
-
- // Constants
- cXMLHttpRequest.UNSENT = 0;
- cXMLHttpRequest.OPENED = 1;
- cXMLHttpRequest.HEADERS_RECEIVED = 2;
- cXMLHttpRequest.LOADING = 3;
- cXMLHttpRequest.DONE = 4;
-
- // Public Properties
- cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;
- cXMLHttpRequest.prototype.responseText = '';
- cXMLHttpRequest.prototype.responseXML = null;
- cXMLHttpRequest.prototype.status = 0;
- cXMLHttpRequest.prototype.statusText = '';
-
- // Priority proposal
- cXMLHttpRequest.prototype.priority = "NORMAL";
-
- // Instance-level Events Handlers
- cXMLHttpRequest.prototype.onreadystatechange = null;
-
- // Class-level Events Handlers
- cXMLHttpRequest.onreadystatechange = null;
- cXMLHttpRequest.onopen = null;
- cXMLHttpRequest.onsend = null;
- cXMLHttpRequest.onabort = null;
-
- // Public Methods
- cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {
- // Delete headers, required when object is reused
- delete this._headers;
-
- // When bAsync parameter value is omitted, use true as default
- if (arguments.length < 3)
- bAsync = true;
-
- // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
- this._async = bAsync;
-
- // Set the onreadystatechange handler
- var oRequest = this,
- nState = this.readyState,
- fOnUnload;
-
- // BUGFIX: IE - memory leak on page unload (inter-page leak)
- if (bIE && bAsync) {
- fOnUnload = function() {
- if (nState != cXMLHttpRequest.DONE) {
- fCleanTransport(oRequest);
- // Safe to abort here since onreadystatechange handler removed
- oRequest.abort();
- }
- };
- window.attachEvent("onunload", fOnUnload);
- }
-
- // Add method sniffer
- if (cXMLHttpRequest.onopen)
- cXMLHttpRequest.onopen.apply(this, arguments);
-
- if (arguments.length > 4)
- this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
- else
- if (arguments.length > 3)
- this._object.open(sMethod, sUrl, bAsync, sUser);
- else
- this._object.open(sMethod, sUrl, bAsync);
-
- this.readyState = cXMLHttpRequest.OPENED;
- fReadyStateChange(this);
-
- this._object.onreadystatechange = function() {
- if (bGecko && !bAsync)
- return;
-
- // Synchronize state
- oRequest.readyState = oRequest._object.readyState;
-
- //
- fSynchronizeValues(oRequest);
-
- // BUGFIX: Firefox fires unnecessary DONE when aborting
- if (oRequest._aborted) {
- // Reset readyState to UNSENT
- oRequest.readyState = cXMLHttpRequest.UNSENT;
-
- // Return now
- return;
- }
-
- if (oRequest.readyState == cXMLHttpRequest.DONE) {
- // Free up queue
- delete oRequest._data;
-/* if (bAsync)
- fQueue_remove(oRequest);*/
- //
- fCleanTransport(oRequest);
-// Uncomment this block if you need a fix for IE cache
-/*
- // BUGFIX: IE - cache issue
- if (!oRequest._object.getResponseHeader("Date")) {
- // Save object to cache
- oRequest._cached = oRequest._object;
-
- // Instantiate a new transport object
- cXMLHttpRequest.call(oRequest);
-
- // Re-send request
- if (sUser) {
- if (sPassword)
- oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
- else
- oRequest._object.open(sMethod, sUrl, bAsync, sUser);
- }
- else
- oRequest._object.open(sMethod, sUrl, bAsync);
- oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
- // Copy headers set
- if (oRequest._headers)
- for (var sHeader in oRequest._headers)
- if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions
- oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
-
- oRequest._object.onreadystatechange = function() {
- // Synchronize state
- oRequest.readyState = oRequest._object.readyState;
-
- if (oRequest._aborted) {
- //
- oRequest.readyState = cXMLHttpRequest.UNSENT;
-
- // Return
- return;
- }
-
- if (oRequest.readyState == cXMLHttpRequest.DONE) {
- // Clean Object
- fCleanTransport(oRequest);
-
- // get cached request
- if (oRequest.status == 304)
- oRequest._object = oRequest._cached;
-
- //
- delete oRequest._cached;
-
- //
- fSynchronizeValues(oRequest);
-
- //
- fReadyStateChange(oRequest);
-
- // BUGFIX: IE - memory leak in interrupted
- if (bIE && bAsync)
- window.detachEvent("onunload", fOnUnload);
- }
- };
- oRequest._object.send(null);
-
- // Return now - wait until re-sent request is finished
- return;
- };
-*/
- // BUGFIX: IE - memory leak in interrupted
- if (bIE && bAsync)
- window.detachEvent("onunload", fOnUnload);
- }
-
- // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
- if (nState != oRequest.readyState)
- fReadyStateChange(oRequest);
-
- nState = oRequest.readyState;
- }
- };
- function fXMLHttpRequest_send(oRequest) {
- oRequest._object.send(oRequest._data);
-
- // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
- if (bGecko && !oRequest._async) {
- oRequest.readyState = cXMLHttpRequest.OPENED;
-
- // Synchronize state
- fSynchronizeValues(oRequest);
-
- // Simulate missing states
- while (oRequest.readyState < cXMLHttpRequest.DONE) {
- oRequest.readyState++;
- fReadyStateChange(oRequest);
- // Check if we are aborted
- if (oRequest._aborted)
- return;
- }
- }
- };
- cXMLHttpRequest.prototype.send = function(vData) {
- // Add method sniffer
- if (cXMLHttpRequest.onsend)
- cXMLHttpRequest.onsend.apply(this, arguments);
-
- if (!arguments.length)
- vData = null;
-
- // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
- // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
- // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
- if (vData && vData.nodeType) {
- vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
- if (!this._headers["Content-Type"])
- this._object.setRequestHeader("Content-Type", "application/xml");
- }
-
- this._data = vData;
-/*
- // Add to queue
- if (this._async)
- fQueue_add(this);
- else*/
- fXMLHttpRequest_send(this);
- };
- cXMLHttpRequest.prototype.abort = function() {
- // Add method sniffer
- if (cXMLHttpRequest.onabort)
- cXMLHttpRequest.onabort.apply(this, arguments);
-
- // BUGFIX: Gecko - unnecessary DONE when aborting
- if (this.readyState > cXMLHttpRequest.UNSENT)
- this._aborted = true;
-
- this._object.abort();
-
- // BUGFIX: IE - memory leak
- fCleanTransport(this);
-
- this.readyState = cXMLHttpRequest.UNSENT;
-
- delete this._data;
-/* if (this._async)
- fQueue_remove(this);*/
- };
- cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
- return this._object.getAllResponseHeaders();
- };
- cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
- return this._object.getResponseHeader(sName);
- };
- cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {
- // BUGFIX: IE - cache issue
- if (!this._headers)
- this._headers = {};
- this._headers[sName] = sValue;
-
- return this._object.setRequestHeader(sName, sValue);
- };
-
- // EventTarget interface implementation
- cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
- return;
- // Add listener
- this._listeners.push([sName, fHandler, bUseCapture]);
- };
-
- cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture)
- break;
- // Remove listener
- if (oListener)
- this._listeners.splice(nIndex, 1);
- };
-
- cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {
- var oEventPseudo = {
- 'type': oEvent.type,
- 'target': this,
- 'currentTarget':this,
- 'eventPhase': 2,
- 'bubbles': oEvent.bubbles,
- 'cancelable': oEvent.cancelable,
- 'timeStamp': oEvent.timeStamp,
- 'stopPropagation': function() {}, // There is no flow
- 'preventDefault': function() {}, // There is no default action
- 'initEvent': function() {} // Original event object should be initialized
- };
-
- // Execute onreadystatechange
- if (oEventPseudo.type == "readystatechange" && this.onreadystatechange)
- (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
-
- // Execute listeners
- for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++)
- if (oListener[0] == oEventPseudo.type && !oListener[2])
- (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
- };
-
- //
- cXMLHttpRequest.prototype.toString = function() {
- return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
- };
-
- cXMLHttpRequest.toString = function() {
- return '[' + "XMLHttpRequest" + ']';
- };
-
- // Helper function
- function fReadyStateChange(oRequest) {
- // Sniffing code
- if (cXMLHttpRequest.onreadystatechange)
- cXMLHttpRequest.onreadystatechange.apply(oRequest);
-
- // Fake event
- oRequest.dispatchEvent({
- 'type': "readystatechange",
- 'bubbles': false,
- 'cancelable': false,
- 'timeStamp': new Date + 0
- });
- };
-
- function fGetDocument(oRequest) {
- var oDocument = oRequest.responseXML,
- sResponse = oRequest.responseText;
- // Try parsing responseText
- if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
- oDocument = new window.ActiveXObject("Microsoft.XMLDOM");
- oDocument.async = false;
- oDocument.validateOnParse = false;
- oDocument.loadXML(sResponse);
- }
- // Check if there is no error in document
- if (oDocument)
- if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror"))
- return null;
- return oDocument;
- };
-
- function fSynchronizeValues(oRequest) {
- try { oRequest.responseText = oRequest._object.responseText; } catch (e) {}
- try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {}
- try { oRequest.status = oRequest._object.status; } catch (e) {}
- try { oRequest.statusText = oRequest._object.statusText; } catch (e) {}
- };
-
- function fCleanTransport(oRequest) {
- // BUGFIX: IE - memory leak (on-page leak)
- oRequest._object.onreadystatechange = new window.Function;
- };
-/*
- // Queue manager
- var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]},
- aQueueRunning = [];
- function fQueue_add(oRequest) {
- oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest);
- //
- setTimeout(fQueue_process);
- };
-
- function fQueue_remove(oRequest) {
- for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)
- if (bFound)
- aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];
- else
- if (aQueueRunning[nIndex] == oRequest)
- bFound = true;
- if (bFound)
- aQueueRunning.length--;
- //
- setTimeout(fQueue_process);
- };
-
- function fQueue_process() {
- if (aQueueRunning.length < 6) {
- for (var sPriority in oQueuePending) {
- if (oQueuePending[sPriority].length) {
- var oRequest = oQueuePending[sPriority][0];
- oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);
- //
- aQueueRunning.push(oRequest);
- // Send request
- fXMLHttpRequest_send(oRequest);
- break;
- }
- }
- }
- };
-*/
- // Internet Explorer 5.0 (missing apply)
- if (!window.Function.prototype.apply) {
- window.Function.prototype.apply = function(oRequest, oArguments) {
- if (!oArguments)
- oArguments = [];
- oRequest.__func = this;
- oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
- delete oRequest.__func;
- };
- };
-
- // Register new object with window
- /**
- * Class: OpenLayers.Request.XMLHttpRequest
- * Standard-compliant (W3C) cross-browser implementation of the
- * XMLHttpRequest object. From
- * http://code.google.com/p/xmlhttprequest/.
- */
- if (!OpenLayers.Request) {
- /**
- * This allows for OpenLayers/Request.js to be included
- * before or after this script.
- */
- OpenLayers.Request = {};
- }
- OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest;
-})();
-/* ======================================================================
- OpenLayers/Format/KML.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Date.js
- * @requires OpenLayers/Format/XML.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/LineString.js
- * @requires OpenLayers/Geometry/Polygon.js
- * @requires OpenLayers/Geometry/Collection.js
- * @requires OpenLayers/Request/XMLHttpRequest.js
- * @requires OpenLayers/Projection.js
- */
-
-/**
- * Class: OpenLayers.Format.KML
- * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format.XML>
- */
-OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
-
- /**
- * Property: namespaces
- * {Object} Mapping of namespace aliases to namespace URIs.
- */
- namespaces: {
- kml: "http://www.opengis.net/kml/2.2",
- gx: "http://www.google.com/kml/ext/2.2"
- },
-
- /**
- * APIProperty: kmlns
- * {String} KML Namespace to use. Defaults to 2.0 namespace.
- */
- kmlns: "http://earth.google.com/kml/2.0",
-
- /**
- * APIProperty: placemarksDesc
- * {String} Name of the placemarks. Default is "No description available".
- */
- placemarksDesc: "No description available",
-
- /**
- * APIProperty: foldersName
- * {String} Name of the folders. Default is "OpenLayers export".
- * If set to null, no name element will be created.
- */
- foldersName: "OpenLayers export",
-
- /**
- * APIProperty: foldersDesc
- * {String} Description of the folders. Default is "Exported on [date]."
- * If set to null, no description element will be created.
- */
- foldersDesc: "Exported on " + new Date(),
-
- /**
- * APIProperty: extractAttributes
- * {Boolean} Extract attributes from KML. Default is true.
- * Extracting styleUrls requires this to be set to true
- * Note that currently only Data and SimpleData
- * elements are handled.
- */
- extractAttributes: true,
-
- /**
- * APIProperty: kvpAttributes
- * {Boolean} Only used if extractAttributes is true.
- * If set to true, attributes will be simple
- * key-value pairs, compatible with other formats,
- * Any displayName elements will be ignored.
- * If set to false, attributes will be objects,
- * retaining any displayName elements, but not
- * compatible with other formats. Any CDATA in
- * displayName will be read in as a string value.
- * Default is false.
- */
- kvpAttributes: false,
-
- /**
- * Property: extractStyles
- * {Boolean} Extract styles from KML. Default is false.
- * Extracting styleUrls also requires extractAttributes to be
- * set to true
- */
- extractStyles: false,
-
- /**
- * APIProperty: extractTracks
- * {Boolean} Extract gx:Track elements from Placemark elements. Default
- * is false. If true, features will be generated for all points in
- * all gx:Track elements. Features will have a when (Date) attribute
- * based on when elements in the track. If tracks include angle
- * elements, features will have heading, tilt, and roll attributes.
- * If track point coordinates have three values, features will have
- * an altitude attribute with the third coordinate value.
- */
- extractTracks: false,
-
- /**
- * APIProperty: trackAttributes
- * {Array} If <extractTracks> is true, points within gx:Track elements will
- * be parsed as features with when, heading, tilt, and roll attributes.
- * Any additional attribute names can be provided in <trackAttributes>.
- */
- trackAttributes: null,
-
- /**
- * Property: internalns
- * {String} KML Namespace to use -- defaults to the namespace of the
- * Placemark node being parsed, but falls back to kmlns.
- */
- internalns: null,
-
- /**
- * Property: features
- * {Array} Array of features
- *
- */
- features: null,
-
- /**
- * Property: styles
- * {Object} Storage of style objects
- *
- */
- styles: null,
-
- /**
- * Property: styleBaseUrl
- * {String}
- */
- styleBaseUrl: "",
-
- /**
- * Property: fetched
- * {Object} Storage of KML URLs that have been fetched before
- * in order to prevent reloading them.
- */
- fetched: null,
-
- /**
- * APIProperty: maxDepth
- * {Integer} Maximum depth for recursive loading external KML URLs
- * Defaults to 0: do no external fetching
- */
- maxDepth: 0,
-
- /**
- * Constructor: OpenLayers.Format.KML
- * Create a new parser for KML.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
- initialize: function(options) {
- // compile regular expressions once instead of every time they are used
- this.regExes = {
- trimSpace: (/^\s*|\s*$/g),
- removeSpace: (/\s*/g),
- splitSpace: (/\s+/),
- trimComma: (/\s*,\s*/g),
- kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/),
- kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/),
- straightBracket: (/\$\[(.*?)\]/g)
- };
- // KML coordinates are always in longlat WGS84
- this.externalProjection = new OpenLayers.Projection("EPSG:4326");
-
- OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
- },
-
- /**
- * APIMethod: read
- * Read data from a string, and return a list of features.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} List of features.
- */
- read: function(data) {
- this.features = [];
- this.styles = {};
- this.fetched = {};
-
- // Set default options
- var options = {
- depth: 0,
- styleBaseUrl: this.styleBaseUrl
- };
-
- return this.parseData(data, options);
- },
-
- /**
- * Method: parseData
- * Read data from a string, and return a list of features.
- *
- * Parameters:
- * data - {String} or {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- * Returns:
- * {Array(<OpenLayers.Feature.Vector>)} List of features.
- */
- parseData: function(data, options) {
- if(typeof data == "string") {
- data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
- }
-
- // Loop throught the following node types in this order and
- // process the nodes found
- var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"];
- for(var i=0, len=types.length; i<len; ++i) {
- var type = types[i];
-
- var nodes = this.getElementsByTagNameNS(data, "*", type);
-
- // skip to next type if no nodes are found
- if(nodes.length == 0) {
- continue;
- }
-
- switch (type.toLowerCase()) {
-
- // Fetch external links
- case "link":
- case "networklink":
- this.parseLinks(nodes, options);
- break;
-
- // parse style information
- case "style":
- if (this.extractStyles) {
- this.parseStyles(nodes, options);
- }
- break;
- case "stylemap":
- if (this.extractStyles) {
- this.parseStyleMaps(nodes, options);
- }
- break;
-
- // parse features
- case "placemark":
- this.parseFeatures(nodes, options);
- break;
- }
- }
-
- return this.features;
- },
-
- /**
- * Method: parseLinks
- * Finds URLs of linked KML documents and fetches them
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseLinks: function(nodes, options) {
-
- // Fetch external links <NetworkLink> and <Link>
- // Don't do anything if we have reached our maximum depth for recursion
- if (options.depth >= this.maxDepth) {
- return false;
- }
-
- // increase depth
- var newOptions = OpenLayers.Util.extend({}, options);
- newOptions.depth++;
-
- for(var i=0, len=nodes.length; i<len; i++) {
- var href = this.parseProperty(nodes[i], "*", "href");
- if(href && !this.fetched[href]) {
- this.fetched[href] = true; // prevent reloading the same urls
- var data = this.fetchLink(href);
- if (data) {
- this.parseData(data, newOptions);
- }
- }
- }
-
- },
-
- /**
- * Method: fetchLink
- * Fetches a URL and returns the result
- *
- * Parameters:
- * href - {String} url to be fetched
- *
- */
- fetchLink: function(href) {
- var request = OpenLayers.Request.GET({url: href, async: false});
- if (request) {
- return request.responseText;
- }
- },
-
- /**
- * Method: parseStyles
- * Parses <Style> nodes
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseStyles: function(nodes, options) {
- for(var i=0, len=nodes.length; i<len; i++) {
- var style = this.parseStyle(nodes[i]);
- if(style) {
- var styleName = (options.styleBaseUrl || "") + "#" + style.id;
-
- this.styles[styleName] = style;
- }
- }
- },
-
- /**
- * Method: parseKmlColor
- * Parses a kml color (in 'aabbggrr' format) and returns the corresponding
- * color and opacity or null if the color is invalid.
- *
- * Parameters:
- * kmlColor - {String} a kml formated color
- *
- * Returns:
- * {Object}
- */
- parseKmlColor: function(kmlColor) {
- var color = null;
- if (kmlColor) {
- var matches = kmlColor.match(this.regExes.kmlColor);
- if (matches) {
- color = {
- color: '#' + matches[4] + matches[3] + matches[2],
- opacity: parseInt(matches[1], 16) / 255
- };
- }
- }
- return color;
- },
-
- /**
- * Method: parseStyle
- * Parses the children of a <Style> node and builds the style hash
- * accordingly
- *
- * Parameters:
- * node - {DOMElement} <Style> node
- *
- */
- parseStyle: function(node) {
- var style = {};
-
- var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle",
- "LabelStyle"];
- var type, styleTypeNode, nodeList, geometry, parser;
- for(var i=0, len=types.length; i<len; ++i) {
- type = types[i];
- styleTypeNode = this.getElementsByTagNameNS(node, "*", type)[0];
- if(!styleTypeNode) {
- continue;
- }
-
- // only deal with first geometry of this type
- switch (type.toLowerCase()) {
- case "linestyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["strokeColor"] = color.color;
- style["strokeOpacity"] = color.opacity;
- }
-
- var width = this.parseProperty(styleTypeNode, "*", "width");
- if (width) {
- style["strokeWidth"] = width;
- }
- break;
-
- case "polystyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["fillOpacity"] = color.opacity;
- style["fillColor"] = color.color;
- }
- // Check if fill is disabled
- var fill = this.parseProperty(styleTypeNode, "*", "fill");
- if (fill == "0") {
- style["fillColor"] = "none";
- }
- // Check if outline is disabled
- var outline = this.parseProperty(styleTypeNode, "*", "outline");
- if (outline == "0") {
- style["strokeWidth"] = "0";
- }
-
- break;
-
- case "iconstyle":
- // set scale
- var scale = parseFloat(this.parseProperty(styleTypeNode,
- "*", "scale") || 1);
-
- // set default width and height of icon
- var width = 32 * scale;
- var height = 32 * scale;
-
- var iconNode = this.getElementsByTagNameNS(styleTypeNode,
- "*",
- "Icon")[0];
- if (iconNode) {
- var href = this.parseProperty(iconNode, "*", "href");
- if (href) {
-
- var w = this.parseProperty(iconNode, "*", "w");
- var h = this.parseProperty(iconNode, "*", "h");
-
- // Settings for Google specific icons that are 64x64
- // We set the width and height to 64 and halve the
- // scale to prevent icons from being too big
- var google = "http://maps.google.com/mapfiles/kml";
- if (OpenLayers.String.startsWith(
- href, google) && !w && !h) {
- w = 64;
- h = 64;
- scale = scale / 2;
- }
-
- // if only dimension is defined, make sure the
- // other one has the same value
- w = w || h;
- h = h || w;
-
- if (w) {
- width = parseInt(w) * scale;
- }
-
- if (h) {
- height = parseInt(h) * scale;
- }
-
- // support for internal icons
- // (/root://icons/palette-x.png)
- // x and y tell the position on the palette:
- // - in pixels
- // - starting from the left bottom
- // We translate that to a position in the list
- // and request the appropriate icon from the
- // google maps website
- var matches = href.match(this.regExes.kmlIconPalette);
- if (matches) {
- var palette = matches[1];
- var file_extension = matches[2];
-
- var x = this.parseProperty(iconNode, "*", "x");
- var y = this.parseProperty(iconNode, "*", "y");
-
- var posX = x ? x/32 : 0;
- var posY = y ? (7 - y/32) : 7;
-
- var pos = posY * 8 + posX;
- href = "http://maps.google.com/mapfiles/kml/pal"
- + palette + "/icon" + pos + file_extension;
- }
-
- style["graphicOpacity"] = 1; // fully opaque
- style["externalGraphic"] = href;
- }
-
- }
-
-
- // hotSpots define the offset for an Icon
- var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode,
- "*",
- "hotSpot")[0];
- if (hotSpotNode) {
- var x = parseFloat(hotSpotNode.getAttribute("x"));
- var y = parseFloat(hotSpotNode.getAttribute("y"));
-
- var xUnits = hotSpotNode.getAttribute("xunits");
- if (xUnits == "pixels") {
- style["graphicXOffset"] = -x * scale;
- }
- else if (xUnits == "insetPixels") {
- style["graphicXOffset"] = -width + (x * scale);
- }
- else if (xUnits == "fraction") {
- style["graphicXOffset"] = -width * x;
- }
-
- var yUnits = hotSpotNode.getAttribute("yunits");
- if (yUnits == "pixels") {
- style["graphicYOffset"] = -height + (y * scale) + 1;
- }
- else if (yUnits == "insetPixels") {
- style["graphicYOffset"] = -(y * scale) + 1;
- }
- else if (yUnits == "fraction") {
- style["graphicYOffset"] = -height * (1 - y) + 1;
- }
- }
-
- style["graphicWidth"] = width;
- style["graphicHeight"] = height;
- break;
-
- case "balloonstyle":
- var balloonStyle = OpenLayers.Util.getXmlNodeValue(
- styleTypeNode);
- if (balloonStyle) {
- style["balloonStyle"] = balloonStyle.replace(
- this.regExes.straightBracket, "${$1}");
- }
- break;
- case "labelstyle":
- var kmlColor = this.parseProperty(styleTypeNode, "*", "color");
- var color = this.parseKmlColor(kmlColor);
- if (color) {
- style["fontColor"] = color.color;
- style["fontOpacity"] = color.opacity;
- }
- break;
-
- default:
- }
- }
-
- // Some polygons have no line color, so we use the fillColor for that
- if (!style["strokeColor"] && style["fillColor"]) {
- style["strokeColor"] = style["fillColor"];
- }
-
- var id = node.getAttribute("id");
- if (id && style) {
- style.id = id;
- }
-
- return style;
- },
-
- /**
- * Method: parseStyleMaps
- * Parses <StyleMap> nodes, but only uses the 'normal' key
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseStyleMaps: function(nodes, options) {
- // Only the default or "normal" part of the StyleMap is processed now
- // To do the select or "highlight" bit, we'd need to change lots more
-
- for(var i=0, len=nodes.length; i<len; i++) {
- var node = nodes[i];
- var pairs = this.getElementsByTagNameNS(node, "*",
- "Pair");
-
- var id = node.getAttribute("id");
- for (var j=0, jlen=pairs.length; j<jlen; j++) {
- var pair = pairs[j];
- // Use the shortcut in the SLD format to quickly retrieve the
- // value of a node. Maybe it's good to have a method in
- // Format.XML to do this
- var key = this.parseProperty(pair, "*", "key");
- var styleUrl = this.parseProperty(pair, "*", "styleUrl");
-
- if (styleUrl && key == "normal") {
- this.styles[(options.styleBaseUrl || "") + "#" + id] =
- this.styles[(options.styleBaseUrl || "") + styleUrl];
- }
-
- // TODO: implement the "select" part
- //if (styleUrl && key == "highlight") {
- //}
-
- }
- }
-
- },
-
-
- /**
- * Method: parseFeatures
- * Loop through all Placemark nodes and parse them.
- * Will create a list of features
- *
- * Parameters:
- * nodes - {Array} of {DOMElement} data to read/parse.
- * options - {Object} Hash of options
- *
- */
- parseFeatures: function(nodes, options) {
- var features = [];
- for(var i=0, len=nodes.length; i<len; i++) {
- var featureNode = nodes[i];
- var feature = this.parseFeature.apply(this,[featureNode]) ;
- if(feature) {
-
- // Create reference to styleUrl
- if (this.extractStyles && feature.attributes &&
- feature.attributes.styleUrl) {
- feature.style = this.getStyle(feature.attributes.styleUrl, options);
- }
-
- if (this.extractStyles) {
- // Make sure that <Style> nodes within a placemark are
- // processed as well
- var inlineStyleNode = this.getElementsByTagNameNS(featureNode,
- "*",
- "Style")[0];
- if (inlineStyleNode) {
- var inlineStyle= this.parseStyle(inlineStyleNode);
- if (inlineStyle) {
- feature.style = OpenLayers.Util.extend(
- feature.style, inlineStyle
- );
- }
- }
- }
-
- // check if gx:Track elements should be parsed
- if (this.extractTracks) {
- var tracks = this.getElementsByTagNameNS(
- featureNode, this.namespaces.gx, "Track"
- );
- if (tracks && tracks.length > 0) {
- var track = tracks[0];
- var container = {
- features: [],
- feature: feature
- };
- this.readNode(track, container);
- if (container.features.length > 0) {
- features.push.apply(features, container.features);
- }
- }
- } else {
- // add feature to list of features
- features.push(feature);
- }
- } else {
- throw "Bad Placemark: " + i;
- }
- }
-
- // add new features to existing feature list
- this.features = this.features.concat(features);
- },
-
- /**
- * 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: {
- "kml": {
- "when": function(node, container) {
- container.whens.push(OpenLayers.Date.parse(
- this.getChildValue(node)
- ));
- },
- "_trackPointAttribute": function(node, container) {
- var name = node.nodeName.split(":").pop();
- container.attributes[name].push(this.getChildValue(node));
- }
- },
- "gx": {
- "Track": function(node, container) {
- var obj = {
- whens: [],
- points: [],
- angles: []
- };
- if (this.trackAttributes) {
- var name;
- obj.attributes = {};
- for (var i=0, ii=this.trackAttributes.length; i<ii; ++i) {
- name = this.trackAttributes[i];
- obj.attributes[name] = [];
- if (!(name in this.readers.kml)) {
- this.readers.kml[name] = this.readers.kml._trackPointAttribute;
- }
- }
- }
- this.readChildNodes(node, obj);
- if (obj.whens.length !== obj.points.length) {
- throw new Error("gx:Track with unequal number of when (" +
- obj.whens.length + ") and gx:coord (" +
- obj.points.length + ") elements.");
- }
- var hasAngles = obj.angles.length > 0;
- if (hasAngles && obj.whens.length !== obj.angles.length) {
- throw new Error("gx:Track with unequal number of when (" +
- obj.whens.length + ") and gx:angles (" +
- obj.angles.length + ") elements.");
- }
- var feature, point, angles;
- for (var i=0, ii=obj.whens.length; i<ii; ++i) {
- feature = container.feature.clone();
- feature.fid = container.feature.fid || container.feature.id;
- point = obj.points[i];
- feature.geometry = point;
- if ("z" in point) {
- feature.attributes.altitude = point.z;
- }
- if (this.internalProjection && this.externalProjection) {
- feature.geometry.transform(
- this.externalProjection, this.internalProjection
- );
- }
- if (this.trackAttributes) {
- for (var j=0, jj=this.trackAttributes.length; j<jj; ++j) {
- var name = this.trackAttributes[j];
- feature.attributes[name] = obj.attributes[name][i];
- }
- }
- feature.attributes.when = obj.whens[i];
- feature.attributes.trackId = container.feature.id;
- if (hasAngles) {
- angles = obj.angles[i];
- feature.attributes.heading = parseFloat(angles[0]);
- feature.attributes.tilt = parseFloat(angles[1]);
- feature.attributes.roll = parseFloat(angles[2]);
- }
- container.features.push(feature);
- }
- },
- "coord": function(node, container) {
- var str = this.getChildValue(node);
- var coords = str.replace(this.regExes.trimSpace, "").split(/\s+/);
- var point = new OpenLayers.Geometry.Point(coords[0], coords[1]);
- if (coords.length > 2) {
- point.z = parseFloat(coords[2]);
- }
- container.points.push(point);
- },
- "angles": function(node, container) {
- var str = this.getChildValue(node);
- var parts = str.replace(this.regExes.trimSpace, "").split(/\s+/);
- container.angles.push(parts);
- }
- }
- },
-
- /**
- * Method: parseFeature
- * This function is the core of the KML parsing code in OpenLayers.
- * It creates the geometries that are then attached to the returned
- * feature, and calls parseAttributes() to get attribute data out.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A vector feature.
- */
- parseFeature: function(node) {
- // only accept one geometry per feature - look for highest "order"
- var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
- var type, nodeList, geometry, parser;
- for(var i=0, len=order.length; i<len; ++i) {
- type = order[i];
- this.internalns = node.namespaceURI ?
- node.namespaceURI : this.kmlns;
- nodeList = this.getElementsByTagNameNS(node,
- this.internalns, type);
- if(nodeList.length > 0) {
- // only deal with first geometry of this type
- var parser = this.parseGeometry[type.toLowerCase()];
- if(parser) {
- geometry = parser.apply(this, [nodeList[0]]);
- if (this.internalProjection && this.externalProjection) {
- geometry.transform(this.externalProjection,
- this.internalProjection);
- }
- } else {
- throw new TypeError("Unsupported geometry type: " + type);
- }
- // stop looking for different geometry types
- break;
- }
- }
-
- // construct feature (optionally with attributes)
- var attributes;
- if(this.extractAttributes) {
- attributes = this.parseAttributes(node);
- }
- var feature = new OpenLayers.Feature.Vector(geometry, attributes);
-
- var fid = node.getAttribute("id") || node.getAttribute("name");
- if(fid != null) {
- feature.fid = fid;
- }
-
- return feature;
- },
-
- /**
- * Method: getStyle
- * Retrieves a style from a style hash using styleUrl as the key
- * If the styleUrl doesn't exist yet, we try to fetch it
- * Internet
- *
- * Parameters:
- * styleUrl - {String} URL of style
- * options - {Object} Hash of options
- *
- * Returns:
- * {Object} - (reference to) Style hash
- */
- getStyle: function(styleUrl, options) {
-
- var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl);
-
- var newOptions = OpenLayers.Util.extend({}, options);
- newOptions.depth++;
- newOptions.styleBaseUrl = styleBaseUrl;
-
- // Fetch remote Style URLs (if not fetched before)
- if (!this.styles[styleUrl]
- && !OpenLayers.String.startsWith(styleUrl, "#")
- && newOptions.depth <= this.maxDepth
- && !this.fetched[styleBaseUrl] ) {
-
- var data = this.fetchLink(styleBaseUrl);
- if (data) {
- this.parseData(data, newOptions);
- }
-
- }
-
- // return requested style
- var style = OpenLayers.Util.extend({}, this.styles[styleUrl]);
- return style;
- },
-
- /**
- * Property: parseGeometry
- * Properties of this object are the functions that parse geometries based
- * on their type.
- */
- parseGeometry: {
-
- /**
- * Method: parseGeometry.point
- * Given a KML node representing a point geometry, create an OpenLayers
- * point geometry.
- *
- * Parameters:
- * node - {DOMElement} A KML Point node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>} A point geometry.
- */
- point: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.internalns,
- "coordinates");
- var coords = [];
- if(nodeList.length > 0) {
- var coordString = nodeList[0].firstChild.nodeValue;
- coordString = coordString.replace(this.regExes.removeSpace, "");
- coords = coordString.split(",");
- }
-
- var point = null;
- if(coords.length > 1) {
- // preserve third dimension
- if(coords.length == 2) {
- coords[2] = null;
- }
- point = new OpenLayers.Geometry.Point(coords[0], coords[1],
- coords[2]);
- } else {
- throw "Bad coordinate string: " + coordString;
- }
- return point;
- },
-
- /**
- * Method: parseGeometry.linestring
- * Given a KML node representing a linestring geometry, create an
- * OpenLayers linestring geometry.
- *
- * Parameters:
- * node - {DOMElement} A KML LineString node.
- *
- * Returns:
- * {<OpenLayers.Geometry.LineString>} A linestring geometry.
- */
- linestring: function(node, ring) {
- var nodeList = this.getElementsByTagNameNS(node, this.internalns,
- "coordinates");
- var line = null;
- if(nodeList.length > 0) {
- var coordString = this.getChildValue(nodeList[0]);
-
- coordString = coordString.replace(this.regExes.trimSpace,
- "");
- coordString = coordString.replace(this.regExes.trimComma,
- ",");
- var pointList = coordString.split(this.regExes.splitSpace);
- var numPoints = pointList.length;
- var points = new Array(numPoints);
- var coords, numCoords;
- for(var i=0; i<numPoints; ++i) {
- coords = pointList[i].split(",");
- numCoords = coords.length;
- if(numCoords > 1) {
- if(coords.length == 2) {
- coords[2] = null;
- }
- points[i] = new OpenLayers.Geometry.Point(coords[0],
- coords[1],
- coords[2]);
- } else {
- throw "Bad LineString point coordinates: " +
- pointList[i];
- }
- }
- if(numPoints) {
- if(ring) {
- line = new OpenLayers.Geometry.LinearRing(points);
- } else {
- line = new OpenLayers.Geometry.LineString(points);
- }
- } else {
- throw "Bad LineString coordinates: " + coordString;
- }
- }
-
- return line;
- },
-
- /**
- * Method: parseGeometry.polygon
- * Given a KML node representing a polygon geometry, create an
- * OpenLayers polygon geometry.
- *
- * Parameters:
- * node - {DOMElement} A KML Polygon node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
- */
- polygon: function(node) {
- var nodeList = this.getElementsByTagNameNS(node, this.internalns,
- "LinearRing");
- var numRings = nodeList.length;
- var components = new Array(numRings);
- if(numRings > 0) {
- // this assumes exterior ring first, inner rings after
- var ring;
- for(var i=0, len=nodeList.length; i<len; ++i) {
- ring = this.parseGeometry.linestring.apply(this,
- [nodeList[i], true]);
- if(ring) {
- components[i] = ring;
- } else {
- throw "Bad LinearRing geometry: " + i;
- }
- }
- }
- return new OpenLayers.Geometry.Polygon(components);
- },
-
- /**
- * Method: parseGeometry.multigeometry
- * Given a KML node representing a multigeometry, create an
- * OpenLayers geometry collection.
- *
- * Parameters:
- * node - {DOMElement} A KML MultiGeometry node.
- *
- * Returns:
- * {<OpenLayers.Geometry.Collection>} A geometry collection.
- */
- multigeometry: function(node) {
- var child, parser;
- var parts = [];
- var children = node.childNodes;
- for(var i=0, len=children.length; i<len; ++i ) {
- child = children[i];
- if(child.nodeType == 1) {
- var type = (child.prefix) ?
- child.nodeName.split(":")[1] :
- child.nodeName;
- var parser = this.parseGeometry[type.toLowerCase()];
- if(parser) {
- parts.push(parser.apply(this, [child]));
- }
- }
- }
- return new OpenLayers.Geometry.Collection(parts);
- }
-
- },
-
- /**
- * Method: parseAttributes
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Object} An attributes object.
- */
- parseAttributes: function(node) {
- var attributes = {};
-
- // Extended Data is parsed first.
- var edNodes = node.getElementsByTagName("ExtendedData");
- if (edNodes.length) {
- attributes = this.parseExtendedData(edNodes[0]);
- }
-
- // assume attribute nodes are type 1 children with a type 3 or 4 child
- var child, grandchildren, grandchild;
- var children = node.childNodes;
-
- for(var i=0, len=children.length; i<len; ++i) {
- child = children[i];
- if(child.nodeType == 1) {
- grandchildren = child.childNodes;
- if(grandchildren.length >= 1 && grandchildren.length <= 3) {
- var grandchild;
- switch (grandchildren.length) {
- case 1:
- grandchild = grandchildren[0];
- break;
- case 2:
- var c1 = grandchildren[0];
- var c2 = grandchildren[1];
- grandchild = (c1.nodeType == 3 || c1.nodeType == 4) ?
- c1 : c2;
- break;
- case 3:
- default:
- grandchild = grandchildren[1];
- break;
- }
- if(grandchild.nodeType == 3 || grandchild.nodeType == 4) {
- var name = (child.prefix) ?
- child.nodeName.split(":")[1] :
- child.nodeName;
- var value = OpenLayers.Util.getXmlNodeValue(grandchild);
- if (value) {
- value = value.replace(this.regExes.trimSpace, "");
- attributes[name] = value;
- }
- }
- }
- }
- }
- return attributes;
- },
-
- /**
- * Method: parseExtendedData
- * Parse ExtendedData from KML. Limited support for schemas/datatypes.
- * See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata
- * for more information on extendeddata.
- */
- parseExtendedData: function(node) {
- var attributes = {};
- var i, len, data, key;
- var dataNodes = node.getElementsByTagName("Data");
- for (i = 0, len = dataNodes.length; i < len; i++) {
- data = dataNodes[i];
- key = data.getAttribute("name");
- var ed = {};
- var valueNode = data.getElementsByTagName("value");
- if (valueNode.length) {
- ed['value'] = this.getChildValue(valueNode[0]);
- }
- if (this.kvpAttributes) {
- attributes[key] = ed['value'];
- } else {
- var nameNode = data.getElementsByTagName("displayName");
- if (nameNode.length) {
- ed['displayName'] = this.getChildValue(nameNode[0]);
- }
- attributes[key] = ed;
- }
- }
- var simpleDataNodes = node.getElementsByTagName("SimpleData");
- for (i = 0, len = simpleDataNodes.length; i < len; i++) {
- var ed = {};
- data = simpleDataNodes[i];
- key = data.getAttribute("name");
- ed['value'] = this.getChildValue(data);
- if (this.kvpAttributes) {
- attributes[key] = ed['value'];
- } else {
- ed['displayName'] = key;
- attributes[key] = ed;
- }
- }
-
- return attributes;
- },
-
- /**
- * Method: parseProperty
- * Convenience method to find a node and return its value
- *
- * Parameters:
- * xmlNode - {<DOMElement>}
- * namespace - {String} namespace of the node to find
- * tagName - {String} name of the property to parse
- *
- * Returns:
- * {String} The value for the requested property (defaults to null)
- */
- parseProperty: function(xmlNode, namespace, tagName) {
- var value;
- var nodeList = this.getElementsByTagNameNS(xmlNode, namespace, tagName);
- try {
- value = OpenLayers.Util.getXmlNodeValue(nodeList[0]);
- } catch(e) {
- value = null;
- }
-
- return value;
- },
-
- /**
- * APIMethod: write
- * Accept Feature Collection, and return a string.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} An array of features.
- *
- * Returns:
- * {String} A KML string.
- */
- write: function(features) {
- if(!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- var kml = this.createElementNS(this.kmlns, "kml");
- var folder = this.createFolderXML();
- for(var i=0, len=features.length; i<len; ++i) {
- folder.appendChild(this.createPlacemarkXML(features[i]));
- }
- kml.appendChild(folder);
- return OpenLayers.Format.XML.prototype.write.apply(this, [kml]);
- },
-
- /**
- * Method: createFolderXML
- * Creates and returns a KML folder node
- *
- * Returns:
- * {DOMElement}
- */
- createFolderXML: function() {
- // Folder
- var folder = this.createElementNS(this.kmlns, "Folder");
-
- // Folder name
- if (this.foldersName) {
- var folderName = this.createElementNS(this.kmlns, "name");
- var folderNameText = this.createTextNode(this.foldersName);
- folderName.appendChild(folderNameText);
- folder.appendChild(folderName);
- }
-
- // Folder description
- if (this.foldersDesc) {
- var folderDesc = this.createElementNS(this.kmlns, "description");
- var folderDescText = this.createTextNode(this.foldersDesc);
- folderDesc.appendChild(folderDescText);
- folder.appendChild(folderDesc);
- }
-
- return folder;
- },
-
- /**
- * Method: createPlacemarkXML
- * Creates and returns a KML placemark node representing the given feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- *
- * Returns:
- * {DOMElement}
- */
- createPlacemarkXML: function(feature) {
- // Placemark name
- var placemarkName = this.createElementNS(this.kmlns, "name");
- var label = (feature.style && feature.style.label) ? feature.style.label : feature.id;
- var name = feature.attributes.name || label;
- placemarkName.appendChild(this.createTextNode(name));
-
- // Placemark description
- var placemarkDesc = this.createElementNS(this.kmlns, "description");
- var desc = feature.attributes.description || this.placemarksDesc;
- placemarkDesc.appendChild(this.createTextNode(desc));
-
- // Placemark
- var placemarkNode = this.createElementNS(this.kmlns, "Placemark");
- if(feature.fid != null) {
- placemarkNode.setAttribute("id", feature.fid);
- }
- placemarkNode.appendChild(placemarkName);
- placemarkNode.appendChild(placemarkDesc);
-
- // Geometry node (Point, LineString, etc. nodes)
- var geometryNode = this.buildGeometryNode(feature.geometry);
- placemarkNode.appendChild(geometryNode);
-
- // output attributes as extendedData
- if (feature.attributes) {
- var edNode = this.buildExtendedData(feature.attributes);
- if (edNode) {
- placemarkNode.appendChild(edNode);
- }
- }
-
- return placemarkNode;
- },
-
- /**
- * Method: buildGeometryNode
- * Builds and returns a KML geometry node with the given geometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
- */
- buildGeometryNode: function(geometry) {
- var className = geometry.CLASS_NAME;
- var type = className.substring(className.lastIndexOf(".") + 1);
- var builder = this.buildGeometry[type.toLowerCase()];
- var node = null;
- if(builder) {
- node = builder.apply(this, [geometry]);
- }
- return node;
- },
-
- /**
- * Property: buildGeometry
- * Object containing methods to do the actual geometry node building
- * based on geometry type.
- */
- buildGeometry: {
- // TBD: Anybody care about namespace aliases here (these nodes have
- // no prefixes)?
-
- /**
- * Method: buildGeometry.point
- * Given an OpenLayers point geometry, create a KML point.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
- *
- * Returns:
- * {DOMElement} A KML point node.
- */
- point: function(geometry) {
- var kml = this.createElementNS(this.kmlns, "Point");
- kml.appendChild(this.buildCoordinatesNode(geometry));
- return kml;
- },
-
- /**
- * Method: buildGeometry.multipoint
- * Given an OpenLayers multipoint geometry, create a KML
- * GeometryCollection.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry.
- *
- * Returns:
- * {DOMElement} A KML GeometryCollection node.
- */
- multipoint: function(geometry) {
- return this.buildGeometry.collection.apply(this, [geometry]);
- },
-
- /**
- * Method: buildGeometry.linestring
- * Given an OpenLayers linestring geometry, create a KML linestring.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
- *
- * Returns:
- * {DOMElement} A KML linestring node.
- */
- linestring: function(geometry) {
- var kml = this.createElementNS(this.kmlns, "LineString");
- kml.appendChild(this.buildCoordinatesNode(geometry));
- return kml;
- },
-
- /**
- * Method: buildGeometry.multilinestring
- * Given an OpenLayers multilinestring geometry, create a KML
- * GeometryCollection.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry.
- *
- * Returns:
- * {DOMElement} A KML GeometryCollection node.
- */
- multilinestring: function(geometry) {
- return this.buildGeometry.collection.apply(this, [geometry]);
- },
-
- /**
- * Method: buildGeometry.linearring
- * Given an OpenLayers linearring geometry, create a KML linearring.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
- *
- * Returns:
- * {DOMElement} A KML linearring node.
- */
- linearring: function(geometry) {
- var kml = this.createElementNS(this.kmlns, "LinearRing");
- kml.appendChild(this.buildCoordinatesNode(geometry));
- return kml;
- },
-
- /**
- * Method: buildGeometry.polygon
- * Given an OpenLayers polygon geometry, create a KML polygon.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
- *
- * Returns:
- * {DOMElement} A KML polygon node.
- */
- polygon: function(geometry) {
- var kml = this.createElementNS(this.kmlns, "Polygon");
- var rings = geometry.components;
- var ringMember, ringGeom, type;
- for(var i=0, len=rings.length; i<len; ++i) {
- type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
- ringMember = this.createElementNS(this.kmlns, type);
- ringGeom = this.buildGeometry.linearring.apply(this,
- [rings[i]]);
- ringMember.appendChild(ringGeom);
- kml.appendChild(ringMember);
- }
- return kml;
- },
-
- /**
- * Method: buildGeometry.multipolygon
- * Given an OpenLayers multipolygon geometry, create a KML
- * GeometryCollection.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry.
- *
- * Returns:
- * {DOMElement} A KML GeometryCollection node.
- */
- multipolygon: function(geometry) {
- return this.buildGeometry.collection.apply(this, [geometry]);
- },
-
- /**
- * Method: buildGeometry.collection
- * Given an OpenLayers geometry collection, create a KML MultiGeometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection.
- *
- * Returns:
- * {DOMElement} A KML MultiGeometry node.
- */
- collection: function(geometry) {
- var kml = this.createElementNS(this.kmlns, "MultiGeometry");
- var child;
- for(var i=0, len=geometry.components.length; i<len; ++i) {
- child = this.buildGeometryNode.apply(this,
- [geometry.components[i]]);
- if(child) {
- kml.appendChild(child);
- }
- }
- return kml;
- }
- },
-
- /**
- * Method: buildCoordinatesNode
- * Builds and returns the KML coordinates node with the given geometry
- * <coordinates>...</coordinates>
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement}
- */
- buildCoordinatesNode: function(geometry) {
- var coordinatesNode = this.createElementNS(this.kmlns, "coordinates");
-
- var path;
- var points = geometry.components;
- if(points) {
- // LineString or LinearRing
- var point;
- var numPoints = points.length;
- var parts = new Array(numPoints);
- for(var i=0; i<numPoints; ++i) {
- point = points[i];
- parts[i] = this.buildCoordinates(point);
- }
- path = parts.join(" ");
- } else {
- // Point
- path = this.buildCoordinates(geometry);
- }
-
- var txtNode = this.createTextNode(path);
- coordinatesNode.appendChild(txtNode);
-
- return coordinatesNode;
- },
-
- /**
- * Method: buildCoordinates
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns
- * {String} a coordinate pair
- */
- buildCoordinates: function(point) {
- if (this.internalProjection && this.externalProjection) {
- point = point.clone();
- point.transform(this.internalProjection,
- this.externalProjection);
- }
- return point.x + "," + point.y;
- },
-
- /**
- * Method: buildExtendedData
- *
- * Parameters:
- * attributes - {Object}
- *
- * Returns
- * {DOMElement} A KML ExtendedData node or {null} if no attributes.
- */
- buildExtendedData: function(attributes) {
- var extendedData = this.createElementNS(this.kmlns, "ExtendedData");
- for (var attributeName in attributes) {
- // empty, name, description, styleUrl attributes ignored
- if (attributes[attributeName] && attributeName != "name" && attributeName != "description" && attributeName != "styleUrl") {
- var data = this.createElementNS(this.kmlns, "Data");
- data.setAttribute("name", attributeName);
- var value = this.createElementNS(this.kmlns, "value");
- if (typeof attributes[attributeName] == "object") {
- // cater for object attributes with 'value' properties
- // other object properties will output an empty node
- if (attributes[attributeName].value) {
- value.appendChild(this.createTextNode(attributes[attributeName].value));
- }
- if (attributes[attributeName].displayName) {
- var displayName = this.createElementNS(this.kmlns, "displayName");
- // displayName always written as CDATA
- displayName.appendChild(this.getXMLDoc().createCDATASection(attributes[attributeName].displayName));
- data.appendChild(displayName);
- }
- } else {
- value.appendChild(this.createTextNode(attributes[attributeName]));
- }
- data.appendChild(value);
- extendedData.appendChild(data);
- }
- }
- if (this.isSimpleContent(extendedData)) {
- return null;
- } else {
- return extendedData;
- }
- },
-
- CLASS_NAME: "OpenLayers.Format.KML"
-});
-/* ======================================================================
- OpenLayers/Protocol/WFS/v1.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Protocol/WFS.js
- */
-
-/**
- * Class: OpenLayers.Protocol.WFS.v1
- * Abstract class for for v1.0.0 and v1.1.0 protocol.
- *
- * Inherits from:
- * - <OpenLayers.Protocol>
- */
-OpenLayers.Protocol.WFS.v1 = OpenLayers.Class(OpenLayers.Protocol, {
-
- /**
- * Property: version
- * {String} WFS version number.
- */
- version: null,
-
- /**
- * Property: srsName
- * {String} Name of spatial reference system. Default is "EPSG:4326".
- */
- srsName: "EPSG:4326",
-
- /**
- * Property: featureType
- * {String} Local feature typeName.
- */
- featureType: null,
-
- /**
- * Property: featureNS
- * {String} Feature namespace.
- */
- featureNS: null,
-
- /**
- * Property: geometryName
- * {String} Name of the geometry attribute for features. Default is
- * "the_geom" for WFS <version> 1.0, and null for higher versions.
- */
- geometryName: "the_geom",
-
- /**
- * Property: maxFeatures
- * {Integer} Optional maximum number of features to retrieve.
- */
-
- /**
- * Property: schema
- * {String} Optional schema location that will be included in the
- * schemaLocation attribute value. Note that the feature type schema
- * is required for a strict XML validator (on transactions with an
- * insert for example), but is *not* required by the WFS specification
- * (since the server is supposed to know about feature type schemas).
- */
- schema: null,
-
- /**
- * Property: featurePrefix
- * {String} Namespace alias for feature type. Default is "feature".
- */
- featurePrefix: "feature",
-
- /**
- * Property: formatOptions
- * {Object} Optional options for the format. If a format is not provided,
- * this property can be used to extend the default format options.
- */
- formatOptions: null,
-
- /**
- * Property: readFormat
- * {<OpenLayers.Format>} For WFS requests it is possible to get a
- * different output format than GML. In that case, we cannot parse
- * the response with the default format (WFST) and we need a different
- * format for reading.
- */
- readFormat: null,
-
- /**
- * Property: readOptions
- * {Object} Optional object to pass to format's read.
- */
- readOptions: null,
-
- /**
- * Constructor: OpenLayers.Protocol.WFS
- * A class for giving layers WFS protocol.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Valid options properties:
- * url - {String} URL to send requests to (required).
- * featureType - {String} Local (without prefix) feature typeName (required).
- * featureNS - {String} Feature namespace (required, but can be autodetected
- * during the first query if GML is used as readFormat and
- * featurePrefix is provided and matches the prefix used by the server
- * for this featureType).
- * featurePrefix - {String} Feature namespace alias (optional - only used
- * for writing if featureNS is provided). Default is 'feature'.
- * geometryName - {String} Name of geometry attribute. The default is
- * 'the_geom' for WFS <version> 1.0, and null for higher versions. If
- * null, it will be set to the name of the first geometry found in the
- * first read operation.
- * multi - {Boolean} If set to true, geometries will be casted to Multi
- * geometries before they are written in a transaction. No casting will
- * be done when reading features.
- */
- initialize: function(options) {
- OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
- if(!options.format) {
- this.format = OpenLayers.Format.WFST(OpenLayers.Util.extend({
- version: this.version,
- featureType: this.featureType,
- featureNS: this.featureNS,
- featurePrefix: this.featurePrefix,
- geometryName: this.geometryName,
- srsName: this.srsName,
- schema: this.schema
- }, this.formatOptions));
- }
- if (!options.geometryName && parseFloat(this.format.version) > 1.0) {
- this.setGeometryName(null);
- }
- },
-
- /**
- * APIMethod: destroy
- * Clean up the protocol.
- */
- destroy: function() {
- if(this.options && !this.options.format) {
- this.format.destroy();
- }
- this.format = null;
- OpenLayers.Protocol.prototype.destroy.apply(this);
- },
-
- /**
- * APIMethod: read
- * Construct a request for reading new features. Since WFS splits the
- * basic CRUD operations into GetFeature requests (for read) and
- * Transactions (for all others), this method does not make use of the
- * format's read method (that is only about reading transaction
- * responses).
- *
- * Parameters:
- * options - {Object} Options for the read operation, in addition to the
- * options set on the instance (options set here will take precedence).
- *
- * To use a configured protocol to get e.g. a WFS hit count, applications
- * could do the following:
- *
- * (code)
- * protocol.read({
- * readOptions: {output: "object"},
- * resultType: "hits",
- * maxFeatures: null,
- * callback: function(resp) {
- * // process resp.numberOfFeatures here
- * }
- * });
- * (end)
- *
- * To use a configured protocol to use WFS paging (if supported by the
- * server), applications could do the following:
- *
- * (code)
- * protocol.read({
- * startIndex: 0,
- * count: 50
- * });
- * (end)
- *
- * To limit the attributes returned by the GetFeature request, applications
- * can use the propertyNames option to specify the properties to include in
- * the response:
- *
- * (code)
- * protocol.read({
- * propertyNames: ["DURATION", "INTENSITY"]
- * });
- * (end)
- */
- read: function(options) {
- OpenLayers.Protocol.prototype.read.apply(this, arguments);
- options = OpenLayers.Util.extend({}, options);
- OpenLayers.Util.applyDefaults(options, this.options || {});
- var response = new OpenLayers.Protocol.Response({requestType: "read"});
-
- var data = OpenLayers.Format.XML.prototype.write.apply(
- this.format, [this.format.writeNode("wfs:GetFeature", options)]
- );
-
- response.priv = OpenLayers.Request.POST({
- url: options.url,
- callback: this.createCallback(this.handleRead, response, options),
- params: options.params,
- headers: options.headers,
- data: data
- });
-
- return response;
- },
-
- /**
- * APIMethod: setFeatureType
- * Change the feature type on the fly.
- *
- * Parameters:
- * featureType - {String} Local (without prefix) feature typeName.
- */
- setFeatureType: function(featureType) {
- this.featureType = featureType;
- this.format.featureType = featureType;
- },
-
- /**
- * APIMethod: setGeometryName
- * Sets the geometryName option after instantiation.
- *
- * Parameters:
- * geometryName - {String} Name of geometry attribute.
- */
- setGeometryName: function(geometryName) {
- this.geometryName = geometryName;
- this.format.geometryName = geometryName;
- },
-
- /**
- * Method: handleRead
- * Deal with response from the read request.
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>} The response object to pass
- * to the user callback.
- * options - {Object} The user options passed to the read call.
- */
- handleRead: function(response, options) {
- options = OpenLayers.Util.extend({}, options);
- OpenLayers.Util.applyDefaults(options, this.options);
-
- if(options.callback) {
- var request = response.priv;
- if(request.status >= 200 && request.status < 300) {
- // success
- var result = this.parseResponse(request, options.readOptions);
- if (result && result.success !== false) {
- if (options.readOptions && options.readOptions.output == "object") {
- OpenLayers.Util.extend(response, result);
- } else {
- response.features = result;
- }
- response.code = OpenLayers.Protocol.Response.SUCCESS;
- } else {
- // failure (service exception)
- response.code = OpenLayers.Protocol.Response.FAILURE;
- response.error = result;
- }
- } else {
- // failure
- response.code = OpenLayers.Protocol.Response.FAILURE;
- }
- options.callback.call(options.scope, response);
- }
- },
-
- /**
- * Method: parseResponse
- * Read HTTP response body and return features
- *
- * Parameters:
- * request - {XMLHttpRequest} The request object
- * options - {Object} Optional object to pass to format's read
- *
- * Returns:
- * {Object} or {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * An object with a features property, an array of features or a single
- * feature.
- */
- parseResponse: function(request, options) {
- var doc = request.responseXML;
- if(!doc || !doc.documentElement) {
- doc = request.responseText;
- }
- if(!doc || doc.length <= 0) {
- return null;
- }
- var result = (this.readFormat !== null) ? this.readFormat.read(doc) :
- this.format.read(doc, options);
- if (!this.featureNS) {
- var format = this.readFormat || this.format;
- this.featureNS = format.featureNS;
- // no need to auto-configure again on subsequent reads
- format.autoConfig = false;
- if (!this.geometryName) {
- this.setGeometryName(format.geometryName);
- }
- }
- return result;
- },
-
- /**
- * Method: commit
- * Given a list of feature, assemble a batch request for update, create,
- * and delete transactions. A commit call on the prototype amounts
- * to writing a WFS transaction - so the write method on the format
- * is used.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- * options - {Object}
- *
- * Valid options properties:
- * nativeElements - {Array({Object})} Array of objects with information for writing
- * out <Native> elements, these objects have vendorId, safeToIgnore and
- * value properties. The <Native> element is intended to allow access to
- * vendor specific capabilities of any particular web feature server or
- * datastore.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} A response object with a features
- * property containing any insertIds and a priv property referencing
- * the XMLHttpRequest object.
- */
- commit: function(features, options) {
-
- options = OpenLayers.Util.extend({}, options);
- OpenLayers.Util.applyDefaults(options, this.options);
-
- var response = new OpenLayers.Protocol.Response({
- requestType: "commit",
- reqFeatures: features
- });
- response.priv = OpenLayers.Request.POST({
- url: options.url,
- headers: options.headers,
- data: this.format.write(features, options),
- callback: this.createCallback(this.handleCommit, response, options)
- });
-
- return response;
- },
-
- /**
- * Method: handleCommit
- * Called when the commit request returns.
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>} The response object to pass
- * to the user callback.
- * options - {Object} The user options passed to the commit call.
- */
- handleCommit: function(response, options) {
- if(options.callback) {
- var request = response.priv;
-
- // ensure that we have an xml doc
- var data = request.responseXML;
- if(!data || !data.documentElement) {
- data = request.responseText;
- }
-
- var obj = this.format.read(data) || {};
-
- response.insertIds = obj.insertIds || [];
- if (obj.success) {
- response.code = OpenLayers.Protocol.Response.SUCCESS;
- } else {
- response.code = OpenLayers.Protocol.Response.FAILURE;
- response.error = obj;
- }
- options.callback.call(options.scope, response);
- }
- },
-
- /**
- * Method: filterDelete
- * Send a request that deletes all features by their filter.
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>} filter
- */
- filterDelete: function(filter, options) {
- options = OpenLayers.Util.extend({}, options);
- OpenLayers.Util.applyDefaults(options, this.options);
-
- var response = new OpenLayers.Protocol.Response({
- requestType: "commit"
- });
-
- var root = this.format.createElementNSPlus("wfs:Transaction", {
- attributes: {
- service: "WFS",
- version: this.version
- }
- });
-
- var deleteNode = this.format.createElementNSPlus("wfs:Delete", {
- attributes: {
- typeName: (options.featureNS ? this.featurePrefix + ":" : "") +
- options.featureType
- }
- });
-
- if(options.featureNS) {
- deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS);
- }
- var filterNode = this.format.writeNode("ogc:Filter", filter);
-
- deleteNode.appendChild(filterNode);
-
- root.appendChild(deleteNode);
-
- var data = OpenLayers.Format.XML.prototype.write.apply(
- this.format, [root]
- );
-
- return OpenLayers.Request.POST({
- url: this.url,
- callback : options.callback || function(){},
- data: data
- });
-
- },
-
- /**
- * Method: abort
- * Abort an ongoing request, the response object passed to
- * this method must come from this protocol (as a result
- * of a read, or commit operation).
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>}
- */
- abort: function(response) {
- if (response) {
- response.priv.abort();
- }
- },
-
- CLASS_NAME: "OpenLayers.Protocol.WFS.v1"
-});
-/* ======================================================================
- OpenLayers/Handler/Feature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Feature
- * Handler to respond to mouse events related to a drawn feature. Callbacks
- * with the following keys will be notified of the following events
- * associated with features: click, clickout, over, out, and dblclick.
- *
- * This handler stops event propagation for mousedown and mouseup if those
- * browser events target features that can be selected.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: EVENTMAP
- * {Object} A object mapping the browser events to objects with callback
- * keys for in and out.
- */
- EVENTMAP: {
- 'click': {'in': 'click', 'out': 'clickout'},
- 'mousemove': {'in': 'over', 'out': 'out'},
- 'dblclick': {'in': 'dblclick', 'out': null},
- 'mousedown': {'in': null, 'out': null},
- 'mouseup': {'in': null, 'out': null},
- 'touchstart': {'in': 'click', 'out': 'clickout'}
- },
-
- /**
- * Property: feature
- * {<OpenLayers.Feature.Vector>} The last feature that was hovered.
- */
- feature: null,
-
- /**
- * Property: lastFeature
- * {<OpenLayers.Feature.Vector>} The last feature that was handled.
- */
- lastFeature: null,
-
- /**
- * Property: down
- * {<OpenLayers.Pixel>} The location of the last mousedown.
- */
- down: null,
-
- /**
- * Property: up
- * {<OpenLayers.Pixel>} The location of the last mouseup.
- */
- up: null,
-
- /**
- * Property: clickTolerance
- * {Number} The number of pixels the mouse can move between mousedown
- * and mouseup for the event to still be considered a click.
- * Dragging the map should not trigger the click and clickout callbacks
- * unless the map is moved by less than this tolerance. Defaults to 4.
- */
- clickTolerance: 4,
-
- /**
- * Property: geometryTypes
- * To restrict dragging to a limited set of geometry types, send a list
- * of strings corresponding to the geometry class names.
- *
- * @type Array(String)
- */
- geometryTypes: null,
-
- /**
- * Property: stopClick
- * {Boolean} If stopClick is set to true, handled clicks do not
- * propagate to other click listeners. Otherwise, handled clicks
- * do propagate. Unhandled clicks always propagate, whatever the
- * value of stopClick. Defaults to true.
- */
- stopClick: true,
-
- /**
- * Property: stopDown
- * {Boolean} If stopDown is set to true, handled mousedowns do not
- * propagate to other mousedown listeners. Otherwise, handled
- * mousedowns do propagate. Unhandled mousedowns always propagate,
- * whatever the value of stopDown. Defaults to true.
- */
- stopDown: true,
-
- /**
- * Property: stopUp
- * {Boolean} If stopUp is set to true, handled mouseups do not
- * propagate to other mouseup listeners. Otherwise, handled mouseups
- * do propagate. Unhandled mouseups always propagate, whatever the
- * value of stopUp. Defaults to false.
- */
- stopUp: false,
-
- /**
- * Constructor: OpenLayers.Handler.Feature
- *
- * Parameters:
- * control - {<OpenLayers.Control>}
- * layer - {<OpenLayers.Layer.Vector>}
- * callbacks - {Object} An object with a 'over' property whos value is
- * a function to be called when the mouse is over a feature. The
- * callback should expect to recieve a single argument, the feature.
- * options - {Object}
- */
- initialize: function(control, layer, callbacks, options) {
- OpenLayers.Handler.prototype.initialize.apply(this, [control, callbacks, options]);
- this.layer = layer;
- },
-
- /**
- * Method: touchstart
- * Handle touchstart events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchstart: function(evt) {
- this.startTouch();
- return OpenLayers.Event.isMultiTouch(evt) ?
- true : this.mousedown(evt);
- },
-
- /**
- * Method: touchmove
- * Handle touchmove events. We just prevent the browser default behavior,
- * for Android Webkit not to select text when moving the finger after
- * selecting a feature.
- *
- * Parameters:
- * evt - {Event}
- */
- touchmove: function(evt) {
- OpenLayers.Event.preventDefault(evt);
- },
-
- /**
- * Method: mousedown
- * Handle mouse down. Stop propagation if a feature is targeted by this
- * event (stops map dragging during feature selection).
- *
- * Parameters:
- * evt - {Event}
- */
- mousedown: function(evt) {
- // Feature selection is only done with a left click. Other handlers may stop the
- // propagation of left-click mousedown events but not right-click mousedown events.
- // This mismatch causes problems when comparing the location of the down and up
- // events in the click function so it is important ignore right-clicks.
- if (OpenLayers.Event.isLeftClick(evt) || OpenLayers.Event.isSingleTouch(evt)) {
- this.down = evt.xy;
- }
- return this.handle(evt) ? !this.stopDown : true;
- },
-
- /**
- * Method: mouseup
- * Handle mouse up. Stop propagation if a feature is targeted by this
- * event.
- *
- * Parameters:
- * evt - {Event}
- */
- mouseup: function(evt) {
- this.up = evt.xy;
- return this.handle(evt) ? !this.stopUp : true;
- },
-
- /**
- * Method: click
- * Handle click. Call the "click" callback if click on a feature,
- * or the "clickout" callback if click outside any feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- click: function(evt) {
- return this.handle(evt) ? !this.stopClick : true;
- },
-
- /**
- * Method: mousemove
- * Handle mouse moves. Call the "over" callback if moving in to a feature,
- * or the "out" callback if moving out of a feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- mousemove: function(evt) {
- if (!this.callbacks['over'] && !this.callbacks['out']) {
- return true;
- }
- this.handle(evt);
- return true;
- },
-
- /**
- * Method: dblclick
- * Handle dblclick. Call the "dblclick" callback if dblclick on a feature.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean}
- */
- dblclick: function(evt) {
- return !this.handle(evt);
- },
-
- /**
- * Method: geometryTypeMatches
- * Return true if the geometry type of the passed feature matches
- * one of the geometry types in the geometryTypes array.
- *
- * Parameters:
- * feature - {<OpenLayers.Vector.Feature>}
- *
- * Returns:
- * {Boolean}
- */
- geometryTypeMatches: function(feature) {
- return this.geometryTypes == null ||
- OpenLayers.Util.indexOf(this.geometryTypes,
- feature.geometry.CLASS_NAME) > -1;
- },
-
- /**
- * Method: handle
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} The event occurred over a relevant feature.
- */
- handle: function(evt) {
- if(this.feature && !this.feature.layer) {
- // feature has been destroyed
- this.feature = null;
- }
- var type = evt.type;
- var handled = false;
- var previouslyIn = !!(this.feature); // previously in a feature
- var click = (type == "click" || type == "dblclick" || type == "touchstart");
- this.feature = this.layer.getFeatureFromEvent(evt);
- if(this.feature && !this.feature.layer) {
- // feature has been destroyed
- this.feature = null;
- }
- if(this.lastFeature && !this.lastFeature.layer) {
- // last feature has been destroyed
- this.lastFeature = null;
- }
- if(this.feature) {
- if(type === "touchstart") {
- // stop the event to prevent Android Webkit from
- // "flashing" the map div
- OpenLayers.Event.preventDefault(evt);
- }
- var inNew = (this.feature != this.lastFeature);
- if(this.geometryTypeMatches(this.feature)) {
- // in to a feature
- if(previouslyIn && inNew) {
- // out of last feature and in to another
- if(this.lastFeature) {
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- this.triggerCallback(type, 'in', [this.feature]);
- } else if(!previouslyIn || click) {
- // in feature for the first time
- this.triggerCallback(type, 'in', [this.feature]);
- }
- this.lastFeature = this.feature;
- handled = true;
- } else {
- // not in to a feature
- if(this.lastFeature && (previouslyIn && inNew || click)) {
- // out of last feature for the first time
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- // next time the mouse goes in a feature whose geometry type
- // doesn't match we don't want to call the 'out' callback
- // again, so let's set this.feature to null so that
- // previouslyIn will evaluate to false the next time
- // we enter handle. Yes, a bit hackish...
- this.feature = null;
- }
- } else if(this.lastFeature && (previouslyIn || click)) {
- this.triggerCallback(type, 'out', [this.lastFeature]);
- }
- return handled;
- },
-
- /**
- * Method: triggerCallback
- * Call the callback keyed in the event map with the supplied arguments.
- * For click and clickout, the <clickTolerance> is checked first.
- *
- * Parameters:
- * type - {String}
- */
- triggerCallback: function(type, mode, args) {
- var key = this.EVENTMAP[type][mode];
- if(key) {
- if(type == 'click' && this.up && this.down) {
- // for click/clickout, only trigger callback if tolerance is met
- var dpx = Math.sqrt(
- Math.pow(this.up.x - this.down.x, 2) +
- Math.pow(this.up.y - this.down.y, 2)
- );
- if(dpx <= this.clickTolerance) {
- this.callback(key, args);
- }
- // we're done with this set of events now: clear the cached
- // positions so we can't trip over them later (this can occur
- // if one of the up/down events gets eaten before it gets to us
- // but we still get the click)
- this.up = this.down = null;
- } else {
- this.callback(key, args);
- }
- }
- },
-
- /**
- * Method: activate
- * Turn on the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean}
- */
- activate: function() {
- var activated = false;
- if(OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.moveLayerToTop();
- this.map.events.on({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Turn off the handler. Returns false if the handler was already active.
- *
- * Returns:
- * {Boolean}
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.moveLayerBack();
- this.feature = null;
- this.lastFeature = null;
- this.down = null;
- this.up = null;
- this.map.events.un({
- "removelayer": this.handleMapEvents,
- "changelayer": this.handleMapEvents,
- scope: this
- });
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method: handleMapEvents
- *
- * Parameters:
- * evt - {Object}
- */
- handleMapEvents: function(evt) {
- if (evt.type == "removelayer" || evt.property == "order") {
- this.moveLayerToTop();
- }
- },
-
- /**
- * Method: moveLayerToTop
- * Moves the layer for this handler to the top, so mouse events can reach
- * it.
- */
- moveLayerToTop: function() {
- var index = Math.max(this.map.Z_INDEX_BASE['Feature'] - 1,
- this.layer.getZIndex()) + 1;
- this.layer.setZIndex(index);
-
- },
-
- /**
- * Method: moveLayerBack
- * Moves the layer back to the position determined by the map's layers
- * array.
- */
- moveLayerBack: function() {
- var index = this.layer.getZIndex() - 1;
- if (index >= this.map.Z_INDEX_BASE['Feature']) {
- this.layer.setZIndex(index);
- } else {
- this.map.setLayerZIndex(this.layer,
- this.map.getLayerIndex(this.layer));
- }
- },
-
- CLASS_NAME: "OpenLayers.Handler.Feature"
-});
-/* ======================================================================
- OpenLayers/StyleMap.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Style.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.StyleMap
- */
-OpenLayers.StyleMap = OpenLayers.Class({
-
- /**
- * Property: styles
- * {Object} Hash of {<OpenLayers.Style>}, keyed by names of well known
- * rendering intents (e.g. "default", "temporary", "select", "delete").
- */
- styles: null,
-
- /**
- * Property: extendDefault
- * {Boolean} if true, every render intent will extend the symbolizers
- * specified for the "default" intent at rendering time. Otherwise, every
- * rendering intent will be treated as a completely independent style.
- */
- extendDefault: true,
-
- /**
- * Constructor: OpenLayers.StyleMap
- *
- * Parameters:
- * style - {Object} Optional. Either a style hash, or a style object, or
- * a hash of style objects (style hashes) keyed by rendering
- * intent. If just one style hash or style object is passed,
- * this will be used for all known render intents (default,
- * select, temporary)
- * options - {Object} optional hash of additional options for this
- * instance
- */
- initialize: function (style, options) {
- this.styles = {
- "default": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["default"]),
- "select": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["select"]),
- "temporary": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["temporary"]),
- "delete": new OpenLayers.Style(
- OpenLayers.Feature.Vector.style["delete"])
- };
-
- // take whatever the user passed as style parameter and convert it
- // into parts of stylemap.
- if(style instanceof OpenLayers.Style) {
- // user passed a style object
- this.styles["default"] = style;
- this.styles["select"] = style;
- this.styles["temporary"] = style;
- this.styles["delete"] = style;
- } else if(typeof style == "object") {
- for(var key in style) {
- if(style[key] instanceof OpenLayers.Style) {
- // user passed a hash of style objects
- this.styles[key] = style[key];
- } else if(typeof style[key] == "object") {
- // user passsed a hash of style hashes
- this.styles[key] = new OpenLayers.Style(style[key]);
- } else {
- // user passed a style hash (i.e. symbolizer)
- this.styles["default"] = new OpenLayers.Style(style);
- this.styles["select"] = new OpenLayers.Style(style);
- this.styles["temporary"] = new OpenLayers.Style(style);
- this.styles["delete"] = new OpenLayers.Style(style);
- break;
- }
- }
- }
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- for(var key in this.styles) {
- this.styles[key].destroy();
- }
- this.styles = null;
- },
-
- /**
- * Method: createSymbolizer
- * Creates the symbolizer for a feature for a render intent.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature>} The feature to evaluate the rules
- * of the intended style against.
- * intent - {String} The intent determines the symbolizer that will be
- * used to draw the feature. Well known intents are "default"
- * (for just drawing the features), "select" (for selected
- * features) and "temporary" (for drawing features).
- *
- * Returns:
- * {Object} symbolizer hash
- */
- createSymbolizer: function(feature, intent) {
- if(!feature) {
- feature = new OpenLayers.Feature.Vector();
- }
- if(!this.styles[intent]) {
- intent = "default";
- }
- feature.renderIntent = intent;
- var defaultSymbolizer = {};
- if(this.extendDefault && intent != "default") {
- defaultSymbolizer = this.styles["default"].createSymbolizer(feature);
- }
- return OpenLayers.Util.extend(defaultSymbolizer,
- this.styles[intent].createSymbolizer(feature));
- },
-
- /**
- * Method: addUniqueValueRules
- * Convenience method to create comparison rules for unique values of a
- * property. The rules will be added to the style object for a specified
- * rendering intent. This method is a shortcut for creating something like
- * the "unique value legends" familiar from well known desktop GIS systems
- *
- * Parameters:
- * renderIntent - {String} rendering intent to add the rules to
- * property - {String} values of feature attributes to create the
- * rules for
- * symbolizers - {Object} Hash of symbolizers, keyed by the desired
- * property values
- * context - {Object} An optional object with properties that
- * symbolizers' property values should be evaluated
- * against. If no context is specified, feature.attributes
- * will be used
- */
- addUniqueValueRules: function(renderIntent, property, symbolizers, context) {
- var rules = [];
- for (var value in symbolizers) {
- rules.push(new OpenLayers.Rule({
- symbolizer: symbolizers[value],
- context: context,
- filter: new OpenLayers.Filter.Comparison({
- type: OpenLayers.Filter.Comparison.EQUAL_TO,
- property: property,
- value: value
- })
- }));
- }
- this.styles[renderIntent].addRules(rules);
- },
-
- CLASS_NAME: "OpenLayers.StyleMap"
-});
-/* ======================================================================
- OpenLayers/Layer/Vector.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer.js
- * @requires OpenLayers/Renderer.js
- * @requires OpenLayers/StyleMap.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Console.js
- * @requires OpenLayers/Lang.js
- */
-
-/**
- * Class: OpenLayers.Layer.Vector
- * Instances of OpenLayers.Layer.Vector are used to render vector data from
- * a variety of sources. Create a new vector layer with the
- * <OpenLayers.Layer.Vector> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer>
- */
-OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
-
- /**
- * 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 (in addition to those from <OpenLayers.Layer.events>):
- * beforefeatureadded - Triggered before a feature is added. Listeners
- * will receive an object with a *feature* property referencing the
- * feature to be added. To stop the feature from being added, a
- * listener should return false.
- * beforefeaturesadded - Triggered before an array of features is added.
- * Listeners will receive an object with a *features* property
- * referencing the feature to be added. To stop the features from
- * being added, a listener should return false.
- * featureadded - Triggered after a feature is added. The event
- * object passed to listeners will have a *feature* property with a
- * reference to the added feature.
- * featuresadded - Triggered after features are added. The event
- * object passed to listeners will have a *features* property with a
- * reference to an array of added features.
- * beforefeatureremoved - Triggered before a feature is removed. Listeners
- * will receive an object with a *feature* property referencing the
- * feature to be removed.
- * beforefeaturesremoved - Triggered before multiple features are removed.
- * Listeners will receive an object with a *features* property
- * referencing the features to be removed.
- * featureremoved - Triggerd after a feature is removed. The event
- * object passed to listeners will have a *feature* property with a
- * reference to the removed feature.
- * featuresremoved - Triggered after features are removed. The event
- * object passed to listeners will have a *features* property with a
- * reference to an array of removed features.
- * beforefeatureselected - Triggered before a feature is selected. Listeners
- * will receive an object with a *feature* property referencing the
- * feature to be selected. To stop the feature from being selectd, a
- * listener should return false.
- * featureselected - Triggered after a feature is selected. Listeners
- * will receive an object with a *feature* property referencing the
- * selected feature.
- * featureunselected - Triggered after a feature is unselected.
- * Listeners will receive an object with a *feature* property
- * referencing the unselected feature.
- * beforefeaturemodified - Triggered when a feature is selected to
- * be modified. Listeners will receive an object with a *feature*
- * property referencing the selected feature.
- * featuremodified - Triggered when a feature has been modified.
- * Listeners will receive an object with a *feature* property referencing
- * the modified feature.
- * afterfeaturemodified - Triggered when a feature is finished being modified.
- * Listeners will receive an object with a *feature* property referencing
- * the modified feature.
- * vertexmodified - Triggered when a vertex within any feature geometry
- * has been modified. Listeners will receive an object with a
- * *feature* property referencing the modified feature, a *vertex*
- * property referencing the vertex modified (always a point geometry),
- * and a *pixel* property referencing the pixel location of the
- * modification.
- * vertexremoved - Triggered when a vertex within any feature geometry
- * has been deleted. Listeners will receive an object with a
- * *feature* property referencing the modified feature, a *vertex*
- * property referencing the vertex modified (always a point geometry),
- * and a *pixel* property referencing the pixel location of the
- * removal.
- * sketchstarted - Triggered when a feature sketch bound for this layer
- * is started. Listeners will receive an object with a *feature*
- * property referencing the new sketch feature and a *vertex* property
- * referencing the creation point.
- * sketchmodified - Triggered when a feature sketch bound for this layer
- * is modified. Listeners will receive an object with a *vertex*
- * property referencing the modified vertex and a *feature* property
- * referencing the sketch feature.
- * sketchcomplete - Triggered when a feature sketch bound for this layer
- * is complete. Listeners will receive an object with a *feature*
- * property referencing the sketch feature. By returning false, a
- * listener can stop the sketch feature from being added to the layer.
- * refresh - Triggered when something wants a strategy to ask the protocol
- * for a new set of features.
- */
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} The layer is a base layer. Default is false. Set this property
- * in the layer options.
- */
- isBaseLayer: false,
-
- /**
- * APIProperty: isFixed
- * {Boolean} Whether the layer remains in one place while dragging the
- * map. Note that setting this to true will move the layer to the bottom
- * of the layer stack.
- */
- isFixed: false,
-
- /**
- * APIProperty: features
- * {Array(<OpenLayers.Feature.Vector>)}
- */
- features: null,
-
- /**
- * Property: filter
- * {<OpenLayers.Filter>} The filter set in this layer,
- * a strategy launching read requests can combined
- * this filter with its own filter.
- */
- filter: null,
-
- /**
- * Property: selectedFeatures
- * {Array(<OpenLayers.Feature.Vector>)}
- */
- selectedFeatures: null,
-
- /**
- * Property: unrenderedFeatures
- * {Object} hash of features, keyed by feature.id, that the renderer
- * failed to draw
- */
- unrenderedFeatures: null,
-
- /**
- * APIProperty: reportError
- * {Boolean} report friendly error message when loading of renderer
- * fails.
- */
- reportError: true,
-
- /**
- * APIProperty: style
- * {Object} Default style for the layer
- */
- style: null,
-
- /**
- * Property: styleMap
- * {<OpenLayers.StyleMap>}
- */
- styleMap: null,
-
- /**
- * Property: strategies
- * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
- */
- strategies: null,
-
- /**
- * Property: protocol
- * {<OpenLayers.Protocol>} Optional protocol for the layer.
- */
- protocol: null,
-
- /**
- * Property: renderers
- * {Array(String)} List of supported Renderer classes. Add to this list to
- * add support for additional renderers. This list is ordered:
- * the first renderer which returns true for the 'supported()'
- * method will be used, if not defined in the 'renderer' option.
- */
- renderers: ['SVG', 'VML', 'Canvas'],
-
- /**
- * Property: renderer
- * {<OpenLayers.Renderer>}
- */
- renderer: null,
-
- /**
- * APIProperty: rendererOptions
- * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
- * supported options.
- */
- rendererOptions: null,
-
- /**
- * APIProperty: geometryType
- * {String} geometryType allows you to limit the types of geometries this
- * layer supports. This should be set to something like
- * "OpenLayers.Geometry.Point" to limit types.
- */
- geometryType: null,
-
- /**
- * Property: drawn
- * {Boolean} Whether the Vector Layer features have been drawn yet.
- */
- drawn: false,
-
- /**
- * APIProperty: ratio
- * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map.
- */
- ratio: 1,
-
- /**
- * Constructor: OpenLayers.Layer.Vector
- * Create a new vector layer
- *
- * Parameters:
- * name - {String} A name for the layer
- * options - {Object} Optional object with non-default properties to set on
- * the layer.
- *
- * Returns:
- * {<OpenLayers.Layer.Vector>} A new vector layer
- */
- initialize: function(name, options) {
- OpenLayers.Layer.prototype.initialize.apply(this, arguments);
-
- // allow user-set renderer, otherwise assign one
- if (!this.renderer || !this.renderer.supported()) {
- this.assignRenderer();
- }
-
- // if no valid renderer found, display error
- if (!this.renderer || !this.renderer.supported()) {
- this.renderer = null;
- this.displayError();
- }
-
- if (!this.styleMap) {
- this.styleMap = new OpenLayers.StyleMap();
- }
-
- this.features = [];
- this.selectedFeatures = [];
- this.unrenderedFeatures = {};
-
- // Allow for custom layer behavior
- if(this.strategies){
- for(var i=0, len=this.strategies.length; i<len; i++) {
- this.strategies[i].setLayer(this);
- }
- }
-
- },
-
- /**
- * APIMethod: destroy
- * Destroy this layer
- */
- destroy: function() {
- if (this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoDestroy) {
- strategy.destroy();
- }
- }
- this.strategies = null;
- }
- if (this.protocol) {
- if(this.protocol.autoDestroy) {
- this.protocol.destroy();
- }
- this.protocol = null;
- }
- this.destroyFeatures();
- this.features = null;
- this.selectedFeatures = null;
- this.unrenderedFeatures = null;
- if (this.renderer) {
- this.renderer.destroy();
- }
- this.renderer = null;
- this.geometryType = null;
- this.drawn = null;
- OpenLayers.Layer.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: clone
- * Create a clone of this layer.
- *
- * Note: Features of the layer are also cloned.
- *
- * Returns:
- * {<OpenLayers.Layer.Vector>} An exact clone of this layer
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.Vector(this.name, this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
- var features = this.features;
- var len = features.length;
- var clonedFeatures = new Array(len);
- for(var i=0; i<len; ++i) {
- clonedFeatures[i] = features[i].clone();
- }
- obj.features = clonedFeatures;
-
- return obj;
- },
-
- /**
- * Method: refresh
- * Ask the layer to request features again and redraw them. Triggers
- * the refresh event if the layer is in range and visible.
- *
- * Parameters:
- * obj - {Object} Optional object with properties for any listener of
- * the refresh event.
- */
- refresh: function(obj) {
- if(this.calculateInRange() && this.visibility) {
- this.events.triggerEvent("refresh", obj);
- }
- },
-
- /**
- * Method: assignRenderer
- * Iterates through the available renderer implementations and selects
- * and assigns the first one whose "supported()" function returns true.
- */
- assignRenderer: function() {
- for (var i=0, len=this.renderers.length; i<len; i++) {
- var rendererClass = this.renderers[i];
- var renderer = (typeof rendererClass == "function") ?
- rendererClass :
- OpenLayers.Renderer[rendererClass];
- if (renderer && renderer.prototype.supported()) {
- this.renderer = new renderer(this.div, this.rendererOptions);
- break;
- }
- }
- },
-
- /**
- * Method: displayError
- * Let the user know their browser isn't supported.
- */
- displayError: function() {
- if (this.reportError) {
- OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",
- {renderers: this. renderers.join('\n')}));
- }
- },
-
- /**
- * Method: setMap
- * The layer has been added to the map.
- *
- * If there is no renderer set, the layer can't be used. Remove it.
- * Otherwise, give the renderer a reference to the map and set its size.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.prototype.setMap.apply(this, arguments);
-
- if (!this.renderer) {
- this.map.removeLayer(this);
- } else {
- this.renderer.map = this.map;
-
- var newSize = this.map.getSize();
- newSize.w = newSize.w * this.ratio;
- newSize.h = newSize.h * this.ratio;
- this.renderer.setSize(newSize);
- }
- },
-
- /**
- * Method: afterAdd
- * Called at the end of the map.addLayer sequence. At this point, the map
- * will have a base layer. Any autoActivate strategies will be
- * activated here.
- */
- afterAdd: function() {
- if(this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoActivate) {
- strategy.activate();
- }
- }
- }
- },
-
- /**
- * Method: removeMap
- * The layer has been removed from the map.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- this.drawn = false;
- if(this.strategies) {
- var strategy, i, len;
- for(i=0, len=this.strategies.length; i<len; i++) {
- strategy = this.strategies[i];
- if(strategy.autoActivate) {
- strategy.deactivate();
- }
- }
- }
- },
-
- /**
- * Method: onMapResize
- * Notify the renderer of the change in size.
- *
- */
- onMapResize: function() {
- OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
-
- var newSize = this.map.getSize();
- newSize.w = newSize.w * this.ratio;
- newSize.h = newSize.h * this.ratio;
- this.renderer.setSize(newSize);
- },
-
- /**
- * Method: moveTo
- * Reset the vector layer's div so that it once again is lined up with
- * the map. Notify the renderer of the change of extent, and in the
- * case of a change of zoom level (resolution), have the
- * renderer redraw features.
- *
- * If the layer has not yet been drawn, cycle through the layer's
- * features and draw each one.
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>}
- * zoomChanged - {Boolean}
- * dragging - {Boolean}
- */
- moveTo: function(bounds, zoomChanged, dragging) {
- OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
-
- var coordSysUnchanged = true;
- if (!dragging) {
- this.renderer.root.style.visibility = 'hidden';
-
- var viewSize = this.map.getSize(),
- viewWidth = viewSize.w,
- viewHeight = viewSize.h,
- offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
- offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
- offsetLeft += this.map.layerContainerOriginPx.x;
- offsetLeft = -Math.round(offsetLeft);
- offsetTop += this.map.layerContainerOriginPx.y;
- offsetTop = -Math.round(offsetTop);
-
- this.div.style.left = offsetLeft + 'px';
- this.div.style.top = offsetTop + 'px';
-
- var extent = this.map.getExtent().scale(this.ratio);
- coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
-
- this.renderer.root.style.visibility = 'visible';
-
- // Force a reflow on gecko based browsers to prevent jump/flicker.
- // This seems to happen on only certain configurations; it was originally
- // noticed in FF 2.0 and Linux.
- if (OpenLayers.IS_GECKO === true) {
- this.div.scrollLeft = this.div.scrollLeft;
- }
-
- if (!zoomChanged && coordSysUnchanged) {
- for (var i in this.unrenderedFeatures) {
- var feature = this.unrenderedFeatures[i];
- this.drawFeature(feature);
- }
- }
- }
- if (!this.drawn || zoomChanged || !coordSysUnchanged) {
- this.drawn = true;
- var feature;
- for(var i=0, len=this.features.length; i<len; i++) {
- this.renderer.locked = (i !== (len - 1));
- feature = this.features[i];
- this.drawFeature(feature);
- }
- }
- },
-
- /**
- * APIMethod: display
- * Hide or show the Layer
- *
- * Parameters:
- * display - {Boolean}
- */
- display: function(display) {
- OpenLayers.Layer.prototype.display.apply(this, arguments);
- // we need to set the display style of the root in case it is attached
- // to a foreign layer
- var currentDisplay = this.div.style.display;
- if(currentDisplay != this.renderer.root.style.display) {
- this.renderer.root.style.display = currentDisplay;
- }
- },
-
- /**
- * APIMethod: addFeatures
- * Add Features to the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- * options - {Object}
- */
- addFeatures: function(features, options) {
- if (!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
-
- var notify = !options || !options.silent;
- if(notify) {
- var event = {features: features};
- var ret = this.events.triggerEvent("beforefeaturesadded", event);
- if(ret === false) {
- return;
- }
- features = event.features;
- }
-
- // Track successfully added features for featuresadded event, since
- // beforefeatureadded can veto single features.
- var featuresAdded = [];
- for (var i=0, len=features.length; i<len; i++) {
- if (i != (features.length - 1)) {
- this.renderer.locked = true;
- } else {
- this.renderer.locked = false;
- }
- var feature = features[i];
-
- if (this.geometryType &&
- !(feature.geometry instanceof this.geometryType)) {
- throw new TypeError('addFeatures: component should be an ' +
- this.geometryType.prototype.CLASS_NAME);
- }
-
- //give feature reference to its layer
- feature.layer = this;
-
- if (!feature.style && this.style) {
- feature.style = OpenLayers.Util.extend({}, this.style);
- }
-
- if (notify) {
- if(this.events.triggerEvent("beforefeatureadded",
- {feature: feature}) === false) {
- continue;
- }
- this.preFeatureInsert(feature);
- }
-
- featuresAdded.push(feature);
- this.features.push(feature);
- this.drawFeature(feature);
-
- if (notify) {
- this.events.triggerEvent("featureadded", {
- feature: feature
- });
- this.onFeatureInsert(feature);
- }
- }
-
- if(notify) {
- this.events.triggerEvent("featuresadded", {features: featuresAdded});
- }
- },
-
-
- /**
- * APIMethod: removeFeatures
- * Remove features from the layer. This erases any drawn features and
- * removes them from the layer's control. The beforefeatureremoved
- * and featureremoved events will be triggered for each feature. The
- * featuresremoved event will be triggered after all features have
- * been removed. To supress event triggering, use the silent option.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
- * removed.
- * options - {Object} Optional properties for changing behavior of the
- * removal.
- *
- * Valid options:
- * silent - {Boolean} Supress event triggering. Default is false.
- */
- removeFeatures: function(features, options) {
- if(!features || features.length === 0) {
- return;
- }
- if (features === this.features) {
- return this.removeAllFeatures(options);
- }
- if (!(OpenLayers.Util.isArray(features))) {
- features = [features];
- }
- if (features === this.selectedFeatures) {
- features = features.slice();
- }
-
- var notify = !options || !options.silent;
-
- if (notify) {
- this.events.triggerEvent(
- "beforefeaturesremoved", {features: features}
- );
- }
-
- for (var i = features.length - 1; i >= 0; i--) {
- // We remain locked so long as we're not at 0
- // and the 'next' feature has a geometry. We do the geometry check
- // because if all the features after the current one are 'null', we
- // won't call eraseGeometry, so we break the 'renderer functions
- // will always be called with locked=false *last*' rule. The end result
- // is a possible gratiutious unlocking to save a loop through the rest
- // of the list checking the remaining features every time. So long as
- // null geoms are rare, this is probably okay.
- if (i != 0 && features[i-1].geometry) {
- this.renderer.locked = true;
- } else {
- this.renderer.locked = false;
- }
-
- var feature = features[i];
- delete this.unrenderedFeatures[feature.id];
-
- if (notify) {
- this.events.triggerEvent("beforefeatureremoved", {
- feature: feature
- });
- }
-
- this.features = OpenLayers.Util.removeItem(this.features, feature);
- // feature has no layer at this point
- feature.layer = null;
-
- if (feature.geometry) {
- this.renderer.eraseFeatures(feature);
- }
-
- //in the case that this feature is one of the selected features,
- // remove it from that array as well.
- if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
- OpenLayers.Util.removeItem(this.selectedFeatures, feature);
- }
-
- if (notify) {
- this.events.triggerEvent("featureremoved", {
- feature: feature
- });
- }
- }
-
- if (notify) {
- this.events.triggerEvent("featuresremoved", {features: features});
- }
- },
-
- /**
- * APIMethod: removeAllFeatures
- * Remove all features from the layer.
- *
- * Parameters:
- * options - {Object} Optional properties for changing behavior of the
- * removal.
- *
- * Valid options:
- * silent - {Boolean} Supress event triggering. Default is false.
- */
- removeAllFeatures: function(options) {
- var notify = !options || !options.silent;
- var features = this.features;
- if (notify) {
- this.events.triggerEvent(
- "beforefeaturesremoved", {features: features}
- );
- }
- var feature;
- for (var i = features.length-1; i >= 0; i--) {
- feature = features[i];
- if (notify) {
- this.events.triggerEvent("beforefeatureremoved", {
- feature: feature
- });
- }
- feature.layer = null;
- if (notify) {
- this.events.triggerEvent("featureremoved", {
- feature: feature
- });
- }
- }
- this.renderer.clear();
- this.features = [];
- this.unrenderedFeatures = {};
- this.selectedFeatures = [];
- if (notify) {
- this.events.triggerEvent("featuresremoved", {features: features});
- }
- },
-
- /**
- * APIMethod: destroyFeatures
- * Erase and destroy features on the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of
- * features to destroy. If not supplied, all features on the layer
- * will be destroyed.
- * options - {Object}
- */
- destroyFeatures: function(features, options) {
- var all = (features == undefined); // evaluates to true if
- // features is null
- if(all) {
- features = this.features;
- }
- if(features) {
- this.removeFeatures(features, options);
- for(var i=features.length-1; i>=0; i--) {
- features[i].destroy();
- }
- }
- },
-
- /**
- * APIMethod: drawFeature
- * Draw (or redraw) a feature on the layer. If the optional style argument
- * is included, this style will be used. If no style is included, the
- * feature's style will be used. If the feature doesn't have a style,
- * the layer's style will be used.
- *
- * This function is not designed to be used when adding features to
- * the layer (use addFeatures instead). It is meant to be used when
- * the style of a feature has changed, or in some other way needs to
- * visually updated *after* it has already been added to a layer. You
- * must add the feature to the layer for most layer-related events to
- * happen.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * style - {String | Object} Named render intent or full symbolizer object.
- */
- drawFeature: function(feature, style) {
- // don't try to draw the feature with the renderer if the layer is not
- // drawn itself
- if (!this.drawn) {
- return;
- }
- if (typeof style != "object") {
- if(!style && feature.state === OpenLayers.State.DELETE) {
- style = "delete";
- }
- var renderIntent = style || feature.renderIntent;
- style = feature.style || this.style;
- if (!style) {
- style = this.styleMap.createSymbolizer(feature, renderIntent);
- }
- }
-
- var drawn = this.renderer.drawFeature(feature, style);
- //TODO remove the check for null when we get rid of Renderer.SVG
- if (drawn === false || drawn === null) {
- this.unrenderedFeatures[feature.id] = feature;
- } else {
- delete this.unrenderedFeatures[feature.id];
- }
- },
-
- /**
- * Method: eraseFeatures
- * Erase features from the layer.
- *
- * Parameters:
- * features - {Array(<OpenLayers.Feature.Vector>)}
- */
- eraseFeatures: function(features) {
- this.renderer.eraseFeatures(features);
- },
-
- /**
- * Method: getFeatureFromEvent
- * Given an event, return a feature if the event occurred over one.
- * Otherwise, return null.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
- */
- getFeatureFromEvent: function(evt) {
- if (!this.renderer) {
- throw new Error('getFeatureFromEvent called on layer with no ' +
- 'renderer. This usually means you destroyed a ' +
- 'layer, but not some handler which is associated ' +
- 'with it.');
- }
- var feature = null;
- var featureId = this.renderer.getFeatureIdFromEvent(evt);
- if (featureId) {
- if (typeof featureId === "string") {
- feature = this.getFeatureById(featureId);
- } else {
- feature = featureId;
- }
- }
- return feature;
- },
-
- /**
- * APIMethod: getFeatureBy
- * Given a property value, return the feature if it exists in the features array
- *
- * Parameters:
- * property - {String}
- * value - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * property value or null if there is no such feature.
- */
- getFeatureBy: function(property, value) {
- //TBD - would it be more efficient to use a hash for this.features?
- var feature = null;
- for(var i=0, len=this.features.length; i<len; ++i) {
- if(this.features[i][property] == value) {
- feature = this.features[i];
- break;
- }
- }
- return feature;
- },
-
- /**
- * APIMethod: getFeatureById
- * Given a feature id, return the feature if it exists in the features array
- *
- * Parameters:
- * featureId - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * featureId or null if there is no such feature.
- */
- getFeatureById: function(featureId) {
- return this.getFeatureBy('id', featureId);
- },
-
- /**
- * APIMethod: getFeatureByFid
- * Given a feature fid, return the feature if it exists in the features array
- *
- * Parameters:
- * featureFid - {String}
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
- * featureFid or null if there is no such feature.
- */
- getFeatureByFid: function(featureFid) {
- return this.getFeatureBy('fid', featureFid);
- },
-
- /**
- * APIMethod: getFeaturesByAttribute
- * Returns an array of features that have the given attribute key set to the
- * given value. Comparison of attribute values takes care of datatypes, e.g.
- * the string '1234' is not equal to the number 1234.
- *
- * Parameters:
- * attrName - {String}
- * attrValue - {Mixed}
- *
- * Returns:
- * Array({<OpenLayers.Feature.Vector>}) An array of features that have the
- * passed named attribute set to the given value.
- */
- getFeaturesByAttribute: function(attrName, attrValue) {
- var i,
- feature,
- len = this.features.length,
- foundFeatures = [];
- for(i = 0; i < len; i++) {
- feature = this.features[i];
- if(feature && feature.attributes) {
- if (feature.attributes[attrName] === attrValue) {
- foundFeatures.push(feature);
- }
- }
- }
- return foundFeatures;
- },
-
- /**
- * Unselect the selected features
- * i.e. clears the featureSelection array
- * change the style back
- clearSelection: function() {
-
- var vectorLayer = this.map.vectorLayer;
- for (var i = 0; i < this.map.featureSelection.length; i++) {
- var featureSelection = this.map.featureSelection[i];
- vectorLayer.drawFeature(featureSelection, vectorLayer.style);
- }
- this.map.featureSelection = [];
- },
- */
-
-
- /**
- * APIMethod: onFeatureInsert
- * method called after a feature is inserted.
- * Does nothing by default. Override this if you
- * need to do something on feature updates.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- onFeatureInsert: function(feature) {
- },
-
- /**
- * APIMethod: preFeatureInsert
- * method called before a feature is inserted.
- * Does nothing by default. Override this if you
- * need to do something when features are first added to the
- * layer, but before they are drawn, such as adjust the style.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- preFeatureInsert: function(feature) {
- },
-
- /**
- * APIMethod: getDataExtent
- * Calculates the max extent which includes all of the features.
- *
- * Returns:
- * {<OpenLayers.Bounds>} or null if the layer has no features with
- * geometries.
- */
- getDataExtent: function () {
- var maxExtent = null;
- var features = this.features;
- if(features && (features.length > 0)) {
- var geometry = null;
- for(var i=0, len=features.length; i<len; i++) {
- geometry = features[i].geometry;
- if (geometry) {
- if (maxExtent === null) {
- maxExtent = new OpenLayers.Bounds();
- }
- maxExtent.extend(geometry.getBounds());
- }
- }
- }
- return maxExtent;
- },
-
- CLASS_NAME: "OpenLayers.Layer.Vector"
-});
-/* ======================================================================
- OpenLayers/Layer/Vector/RootContainer.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Layer/Vector.js
- */
-
-/**
- * Class: OpenLayers.Layer.Vector.RootContainer
- * A special layer type to combine multiple vector layers inside a single
- * renderer root container. This class is not supposed to be instantiated
- * from user space, it is a helper class for controls that require event
- * processing for multiple vector layers.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Vector>
- */
-OpenLayers.Layer.Vector.RootContainer = OpenLayers.Class(OpenLayers.Layer.Vector, {
-
- /**
- * Property: displayInLayerSwitcher
- * Set to false for this layer type
- */
- displayInLayerSwitcher: false,
-
- /**
- * APIProperty: layers
- * Layers that are attached to this container. Required config option.
- */
- layers: null,
-
- /**
- * Constructor: OpenLayers.Layer.Vector.RootContainer
- * Create a new root container for multiple vector layer. This constructor
- * is not supposed to be used from user space, it is only to be used by
- * controls that need feature selection across multiple vector layers.
- *
- * Parameters:
- * name - {String} A name for the layer
- * options - {Object} Optional object with non-default properties to set on
- * the layer.
- *
- * Required options properties:
- * layers - {Array(<OpenLayers.Layer.Vector>)} The layers managed by this
- * container
- *
- * Returns:
- * {<OpenLayers.Layer.Vector.RootContainer>} A new vector layer root
- * container
- */
-
- /**
- * Method: display
- */
- display: function() {},
-
- /**
- * Method: getFeatureFromEvent
- * walk through the layers to find the feature returned by the event
- *
- * Parameters:
- * evt - {Object} event object with a feature property
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>}
- */
- getFeatureFromEvent: function(evt) {
- var layers = this.layers;
- var feature;
- for(var i=0; i<layers.length; i++) {
- feature = layers[i].getFeatureFromEvent(evt);
- if(feature) {
- return feature;
- }
- }
- },
-
- /**
- * Method: setMap
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments);
- this.collectRoots();
- map.events.register("changelayer", this, this.handleChangeLayer);
- },
-
- /**
- * Method: removeMap
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- map.events.unregister("changelayer", this, this.handleChangeLayer);
- this.resetRoots();
- OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments);
- },
-
- /**
- * Method: collectRoots
- * Collects the root nodes of all layers this control is configured with
- * and moveswien the nodes to this control's layer
- */
- collectRoots: function() {
- var layer;
- // walk through all map layers, because we want to keep the order
- for(var i=0; i<this.map.layers.length; ++i) {
- layer = this.map.layers[i];
- if(OpenLayers.Util.indexOf(this.layers, layer) != -1) {
- layer.renderer.moveRoot(this.renderer);
- }
- }
- },
-
- /**
- * Method: resetRoots
- * Resets the root nodes back into the layers they belong to.
- */
- resetRoots: function() {
- var layer;
- for(var i=0; i<this.layers.length; ++i) {
- layer = this.layers[i];
- if(this.renderer && layer.renderer.getRenderLayerId() == this.id) {
- this.renderer.moveRoot(layer.renderer);
- }
- }
- },
-
- /**
- * Method: handleChangeLayer
- * Event handler for the map's changelayer event. We need to rebuild
- * this container's layer dom if order of one of its layers changes.
- * This handler is added with the setMap method, and removed with the
- * removeMap method.
- *
- * Parameters:
- * evt - {Object}
- */
- handleChangeLayer: function(evt) {
- var layer = evt.layer;
- if(evt.property == "order" &&
- OpenLayers.Util.indexOf(this.layers, layer) != -1) {
- this.resetRoots();
- this.collectRoots();
- }
- },
-
- CLASS_NAME: "OpenLayers.Layer.Vector.RootContainer"
-});
-/* ======================================================================
- OpenLayers/Control/SelectFeature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Handler/Feature.js
- * @requires OpenLayers/Layer/Vector/RootContainer.js
- */
-
-/**
- * Class: OpenLayers.Control.SelectFeature
- * The SelectFeature control selects vector features from a given layer on
- * click or hover.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * 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)
- *
- * Supported event types (in addition to those from <OpenLayers.Control.events>):
- * beforefeaturehighlighted - Triggered before a feature is highlighted
- * featurehighlighted - Triggered when a feature is highlighted
- * featureunhighlighted - Triggered when a feature is unhighlighted
- * boxselectionstart - Triggered before box selection starts
- * boxselectionend - Triggered after box selection ends
- */
-
- /**
- * Property: multipleKey
- * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
- * the <multiple> property to true. Default is null.
- */
- multipleKey: null,
-
- /**
- * Property: toggleKey
- * {String} An event modifier ('altKey' or 'shiftKey') that temporarily sets
- * the <toggle> property to true. Default is null.
- */
- toggleKey: null,
-
- /**
- * APIProperty: multiple
- * {Boolean} Allow selection of multiple geometries. Default is false.
- */
- multiple: false,
-
- /**
- * APIProperty: clickout
- * {Boolean} Unselect features when clicking outside any feature.
- * Default is true.
- */
- clickout: true,
-
- /**
- * APIProperty: toggle
- * {Boolean} Unselect a selected feature on click. Default is false. Only
- * has meaning if hover is false.
- */
- toggle: false,
-
- /**
- * APIProperty: hover
- * {Boolean} Select on mouse over and deselect on mouse out. If true, this
- * ignores clicks and only listens to mouse moves.
- */
- hover: false,
-
- /**
- * APIProperty: highlightOnly
- * {Boolean} If true do not actually select features (that is place them in
- * the layer's selected features array), just highlight them. This property
- * has no effect if hover is false. Defaults to false.
- */
- highlightOnly: false,
-
- /**
- * APIProperty: box
- * {Boolean} Allow feature selection by drawing a box.
- */
- box: false,
-
- /**
- * Property: onBeforeSelect
- * {Function} Optional function to be called before a feature is selected.
- * The function should expect to be called with a feature.
- */
- onBeforeSelect: function() {},
-
- /**
- * APIProperty: onSelect
- * {Function} Optional function to be called when a feature is selected.
- * The function should expect to be called with a feature.
- */
- onSelect: function() {},
-
- /**
- * APIProperty: onUnselect
- * {Function} Optional function to be called when a feature is unselected.
- * The function should expect to be called with a feature.
- */
- onUnselect: function() {},
-
- /**
- * Property: scope
- * {Object} The scope to use with the onBeforeSelect, onSelect, onUnselect
- * callbacks. If null the scope will be this control.
- */
- scope: null,
-
- /**
- * APIProperty: geometryTypes
- * {Array(String)} To restrict selecting to a limited set of geometry types,
- * send a list of strings corresponding to the geometry class names.
- */
- geometryTypes: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The vector layer with a common renderer
- * root for all layers this control is configured with (if an array of
- * layers was passed to the constructor), or the vector layer the control
- * was configured with (if a single layer was passed to the constructor).
- */
- layer: null,
-
- /**
- * Property: layers
- * {Array(<OpenLayers.Layer.Vector>)} The layers this control will work on,
- * or null if the control was configured with a single layer
- */
- layers: null,
-
- /**
- * APIProperty: callbacks
- * {Object} The functions that are sent to the handlers.feature for callback
- */
- callbacks: null,
-
- /**
- * APIProperty: selectStyle
- * {Object} Hash of styles
- */
- selectStyle: null,
-
- /**
- * Property: renderIntent
- * {String} key used to retrieve the select style from the layer's
- * style map.
- */
- renderIntent: "select",
-
- /**
- * Property: handlers
- * {Object} Object with references to multiple <OpenLayers.Handler>
- * instances.
- */
- handlers: null,
-
- /**
- * Constructor: OpenLayers.Control.SelectFeature
- * Create a new control for selecting features.
- *
- * Parameters:
- * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers. The
- * layer(s) this control will select features from.
- * options - {Object}
- */
- initialize: function(layers, options) {
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
-
- if(this.scope === null) {
- this.scope = this;
- }
- this.initLayer(layers);
- var callbacks = {
- click: this.clickFeature,
- clickout: this.clickoutFeature
- };
- if (this.hover) {
- callbacks.over = this.overFeature;
- callbacks.out = this.outFeature;
- }
-
- this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks);
- this.handlers = {
- feature: new OpenLayers.Handler.Feature(
- this, this.layer, this.callbacks,
- {geometryTypes: this.geometryTypes}
- )
- };
-
- if (this.box) {
- this.handlers.box = new OpenLayers.Handler.Box(
- this, {done: this.selectBox},
- {boxDivClassName: "olHandlerBoxSelectFeature"}
- );
- }
- },
-
- /**
- * Method: initLayer
- * Assign the layer property. If layers is an array, we need to use
- * a RootContainer.
- *
- * Parameters:
- * layers - {<OpenLayers.Layer.Vector>}, or an array of vector layers.
- */
- initLayer: function(layers) {
- if(OpenLayers.Util.isArray(layers)) {
- this.layers = layers;
- this.layer = new OpenLayers.Layer.Vector.RootContainer(
- this.id + "_container", {
- layers: layers
- }
- );
- } else {
- this.layer = layers;
- }
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- if(this.active && this.layers) {
- this.map.removeLayer(this.layer);
- }
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- if(this.layers) {
- this.layer.destroy();
- }
- },
-
- /**
- * Method: activate
- * Activates the control.
- *
- * Returns:
- * {Boolean} The control was effectively activated.
- */
- activate: function () {
- if (!this.active) {
- if(this.layers) {
- this.map.addLayer(this.layer);
- }
- this.handlers.feature.activate();
- if(this.box && this.handlers.box) {
- this.handlers.box.activate();
- }
- }
- return OpenLayers.Control.prototype.activate.apply(
- this, arguments
- );
- },
-
- /**
- * Method: deactivate
- * Deactivates the control.
- *
- * Returns:
- * {Boolean} The control was effectively deactivated.
- */
- deactivate: function () {
- if (this.active) {
- this.handlers.feature.deactivate();
- if(this.handlers.box) {
- this.handlers.box.deactivate();
- }
- if(this.layers) {
- this.map.removeLayer(this.layer);
- }
- }
- return OpenLayers.Control.prototype.deactivate.apply(
- this, arguments
- );
- },
-
- /**
- * Method: unselectAll
- * Unselect all selected features. To unselect all except for a single
- * feature, set the options.except property to the feature.
- *
- * Parameters:
- * options - {Object} Optional configuration object.
- */
- unselectAll: function(options) {
- // we'll want an option to supress notification here
- var layers = this.layers || [this.layer],
- layer, feature, l, numExcept;
- for(l=0; l<layers.length; ++l) {
- layer = layers[l];
- numExcept = 0;
- //layer.selectedFeatures is null when layer is destroyed and
- //one of it's preremovelayer listener calls setLayer
- //with another layer on this control
- if(layer.selectedFeatures != null) {
- while(layer.selectedFeatures.length > numExcept) {
- feature = layer.selectedFeatures[numExcept];
- if(!options || options.except != feature) {
- this.unselect(feature);
- } else {
- ++numExcept;
- }
- }
- }
- }
- },
-
- /**
- * Method: clickFeature
- * Called on click in a feature
- * Only responds if this.hover is false.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- clickFeature: function(feature) {
- if(!this.hover) {
- var selected = (OpenLayers.Util.indexOf(
- feature.layer.selectedFeatures, feature) > -1);
- if(selected) {
- if(this.toggleSelect()) {
- this.unselect(feature);
- } else if(!this.multipleSelect()) {
- this.unselectAll({except: feature});
- }
- } else {
- if(!this.multipleSelect()) {
- this.unselectAll({except: feature});
- }
- this.select(feature);
- }
- }
- },
-
- /**
- * Method: multipleSelect
- * Allow for multiple selected features based on <multiple> property and
- * <multipleKey> event modifier.
- *
- * Returns:
- * {Boolean} Allow for multiple selected features.
- */
- multipleSelect: function() {
- return this.multiple || (this.handlers.feature.evt &&
- this.handlers.feature.evt[this.multipleKey]);
- },
-
- /**
- * Method: toggleSelect
- * Event should toggle the selected state of a feature based on <toggle>
- * property and <toggleKey> event modifier.
- *
- * Returns:
- * {Boolean} Toggle the selected state of a feature.
- */
- toggleSelect: function() {
- return this.toggle || (this.handlers.feature.evt &&
- this.handlers.feature.evt[this.toggleKey]);
- },
-
- /**
- * Method: clickoutFeature
- * Called on click outside a previously clicked (selected) feature.
- * Only responds if this.hover is false.
- *
- * Parameters:
- * feature - {<OpenLayers.Vector.Feature>}
- */
- clickoutFeature: function(feature) {
- if(!this.hover && this.clickout) {
- this.unselectAll();
- }
- },
-
- /**
- * Method: overFeature
- * Called on over a feature.
- * Only responds if this.hover is true.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- overFeature: function(feature) {
- var layer = feature.layer;
- if(this.hover) {
- if(this.highlightOnly) {
- this.highlight(feature);
- } else if(OpenLayers.Util.indexOf(
- layer.selectedFeatures, feature) == -1) {
- this.select(feature);
- }
- }
- },
-
- /**
- * Method: outFeature
- * Called on out of a selected feature.
- * Only responds if this.hover is true.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- outFeature: function(feature) {
- if(this.hover) {
- if(this.highlightOnly) {
- // we do nothing if we're not the last highlighter of the
- // feature
- if(feature._lastHighlighter == this.id) {
- // if another select control had highlighted the feature before
- // we did it ourself then we use that control to highlight the
- // feature as it was before we highlighted it, else we just
- // unhighlight it
- if(feature._prevHighlighter &&
- feature._prevHighlighter != this.id) {
- delete feature._lastHighlighter;
- var control = this.map.getControl(
- feature._prevHighlighter);
- if(control) {
- control.highlight(feature);
- }
- } else {
- this.unhighlight(feature);
- }
- }
- } else {
- this.unselect(feature);
- }
- }
- },
-
- /**
- * Method: highlight
- * Redraw feature with the select style.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- highlight: function(feature) {
- var layer = feature.layer;
- var cont = this.events.triggerEvent("beforefeaturehighlighted", {
- feature : feature
- });
- if(cont !== false) {
- feature._prevHighlighter = feature._lastHighlighter;
- feature._lastHighlighter = this.id;
- var style = this.selectStyle || this.renderIntent;
- layer.drawFeature(feature, style);
- this.events.triggerEvent("featurehighlighted", {feature : feature});
- }
- },
-
- /**
- * Method: unhighlight
- * Redraw feature with the "default" style
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- unhighlight: function(feature) {
- var layer = feature.layer;
- // three cases:
- // 1. there's no other highlighter, in that case _prev is undefined,
- // and we just need to undef _last
- // 2. another control highlighted the feature after we did it, in
- // that case _last references this other control, and we just
- // need to undef _prev
- // 3. another control highlighted the feature before we did it, in
- // that case _prev references this other control, and we need to
- // set _last to _prev and undef _prev
- if(feature._prevHighlighter == undefined) {
- delete feature._lastHighlighter;
- } else if(feature._prevHighlighter == this.id) {
- delete feature._prevHighlighter;
- } else {
- feature._lastHighlighter = feature._prevHighlighter;
- delete feature._prevHighlighter;
- }
- layer.drawFeature(feature, feature.style || feature.layer.style ||
- "default");
- this.events.triggerEvent("featureunhighlighted", {feature : feature});
- },
-
- /**
- * Method: select
- * Add feature to the layer's selectedFeature array, render the feature as
- * selected, and call the onSelect function.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- select: function(feature) {
- var cont = this.onBeforeSelect.call(this.scope, feature);
- var layer = feature.layer;
- if(cont !== false) {
- cont = layer.events.triggerEvent("beforefeatureselected", {
- feature: feature
- });
- if(cont !== false) {
- layer.selectedFeatures.push(feature);
- this.highlight(feature);
- // if the feature handler isn't involved in the feature
- // selection (because the box handler is used or the
- // feature is selected programatically) we fake the
- // feature handler to allow unselecting on click
- if(!this.handlers.feature.lastFeature) {
- this.handlers.feature.lastFeature = layer.selectedFeatures[0];
- }
- layer.events.triggerEvent("featureselected", {feature: feature});
- this.onSelect.call(this.scope, feature);
- }
- }
- },
-
- /**
- * Method: unselect
- * Remove feature from the layer's selectedFeature array, render the feature as
- * normal, and call the onUnselect function.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- */
- unselect: function(feature) {
- var layer = feature.layer;
- // Store feature style for restoration later
- this.unhighlight(feature);
- OpenLayers.Util.removeItem(layer.selectedFeatures, feature);
- layer.events.triggerEvent("featureunselected", {feature: feature});
- this.onUnselect.call(this.scope, feature);
- },
-
- /**
- * Method: selectBox
- * Callback from the handlers.box set up when <box> selection is true
- * on.
- *
- * Parameters:
- * position - {<OpenLayers.Bounds> || <OpenLayers.Pixel> }
- */
- selectBox: function(position) {
- if (position instanceof OpenLayers.Bounds) {
- var minXY = this.map.getLonLatFromPixel({
- x: position.left,
- y: position.bottom
- });
- var maxXY = this.map.getLonLatFromPixel({
- x: position.right,
- y: position.top
- });
- var bounds = new OpenLayers.Bounds(
- minXY.lon, minXY.lat, maxXY.lon, maxXY.lat
- );
-
- // if multiple is false, first deselect currently selected features
- if (!this.multipleSelect()) {
- this.unselectAll();
- }
-
- // because we're using a box, we consider we want multiple selection
- var prevMultiple = this.multiple;
- this.multiple = true;
- var layers = this.layers || [this.layer];
- this.events.triggerEvent("boxselectionstart", {layers: layers});
- var layer;
- for(var l=0; l<layers.length; ++l) {
- layer = layers[l];
- for(var i=0, len = layer.features.length; i<len; ++i) {
- var feature = layer.features[i];
- // check if the feature is displayed
- if (!feature.getVisibility()) {
- continue;
- }
-
- if (this.geometryTypes == null || OpenLayers.Util.indexOf(
- this.geometryTypes, feature.geometry.CLASS_NAME) > -1) {
- if (bounds.toGeometry().intersects(feature.geometry)) {
- if (OpenLayers.Util.indexOf(layer.selectedFeatures, feature) == -1) {
- this.select(feature);
- }
- }
- }
- }
- }
- this.multiple = prevMultiple;
- this.events.triggerEvent("boxselectionend", {layers: layers});
- }
- },
-
- /**
- * Method: setMap
- * Set the map property for the control.
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- setMap: function(map) {
- this.handlers.feature.setMap(map);
- if (this.box) {
- this.handlers.box.setMap(map);
- }
- OpenLayers.Control.prototype.setMap.apply(this, arguments);
- },
-
- /**
- * APIMethod: setLayer
- * Attach a new layer to the control, overriding any existing layers.
- *
- * Parameters:
- * layers - Array of {<OpenLayers.Layer.Vector>} or a single
- * {<OpenLayers.Layer.Vector>}
- */
- setLayer: function(layers) {
- var isActive = this.active;
- this.unselectAll();
- this.deactivate();
- if(this.layers) {
- this.layer.destroy();
- this.layers = null;
- }
- this.initLayer(layers);
- this.handlers.feature.layer = this.layer;
- if (isActive) {
- this.activate();
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.SelectFeature"
-});
-/* ======================================================================
- OpenLayers/Handler/Point.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler.js
- * @requires OpenLayers/Geometry/Point.js
- */
-
-/**
- * Class: OpenLayers.Handler.Point
- * Handler to draw a point on the map. Point is displayed on activation,
- * moves on mouse move, and is finished on mouse up. The handler triggers
- * callbacks for 'done', 'cancel', and 'modify'. The modify callback is
- * called with each change in the sketch and will receive the latest point
- * drawn. Create a new instance with the <OpenLayers.Handler.Point>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: point
- * {<OpenLayers.Feature.Vector>} The currently drawn point
- */
- point: null,
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>} The temporary drawing layer
- */
- layer: null,
-
- /**
- * APIProperty: multi
- * {Boolean} Cast features to multi-part geometries before passing to the
- * layer. Default is false.
- */
- multi: false,
-
- /**
- * APIProperty: citeCompliant
- * {Boolean} If set to true, coordinates of features drawn in a map extent
- * crossing the date line won't exceed the world bounds. Default is false.
- */
- citeCompliant: false,
-
- /**
- * Property: mouseDown
- * {Boolean} The mouse is down
- */
- mouseDown: false,
-
- /**
- * Property: stoppedDown
- * {Boolean} Indicate whether the last mousedown stopped the event
- * propagation.
- */
- stoppedDown: null,
-
- /**
- * Property: lastDown
- * {<OpenLayers.Pixel>} Location of the last mouse down
- */
- lastDown: null,
-
- /**
- * Property: lastUp
- * {<OpenLayers.Pixel>}
- */
- lastUp: null,
-
- /**
- * APIProperty: persist
- * {Boolean} Leave the feature rendered until destroyFeature is called.
- * Default is false. If set to true, the feature remains rendered until
- * destroyFeature is called, typically by deactivating the handler or
- * starting another drawing.
- */
- persist: false,
-
- /**
- * APIProperty: stopDown
- * {Boolean} Stop event propagation on mousedown. Must be false to
- * allow "pan while drawing". Defaults to false.
- */
- stopDown: false,
-
- /**
- * APIPropery: stopUp
- * {Boolean} Stop event propagation on mouse. Must be false to
- * allow "pan while dragging". Defaults to fase.
- */
- stopUp: false,
-
- /**
- * Property: layerOptions
- * {Object} Any optional properties to be set on the sketch layer.
- */
- layerOptions: null,
-
- /**
- * APIProperty: pixelTolerance
- * {Number} Maximum number of pixels between down and up (mousedown
- * and mouseup, or touchstart and touchend) for the handler to
- * add a new point. If set to an integer value, if the
- * displacement between down and up is great to this value
- * no point will be added. Default value is 5.
- */
- pixelTolerance: 5,
-
- /**
- * Property: lastTouchPx
- * {<OpenLayers.Pixel>} The last pixel used to know the distance between
- * two touches (for double touch).
- */
- lastTouchPx: null,
-
- /**
- * Constructor: OpenLayers.Handler.Point
- * Create a new point handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the point geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
- initialize: function(control, callbacks, options) {
- if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
- this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
- }
-
- OpenLayers.Handler.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * APIMethod: activate
- * turn on the handler
- */
- activate: function() {
- if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- return false;
- }
- // create temporary vector layer for rendering geometry sketch
- // TBD: this could be moved to initialize/destroy - setting visibility here
- var options = OpenLayers.Util.extend({
- displayInLayerSwitcher: false,
- // indicate that the temp vector layer will never be out of range
- // without this, resolution properties must be specified at the
- // map-level for this temporary layer to init its resolutions
- // correctly
- calculateInRange: OpenLayers.Function.True,
- wrapDateLine: this.citeCompliant
- }, this.layerOptions);
- this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
- this.map.addLayer(this.layer);
- return true;
- },
-
- /**
- * Method: createFeature
- * Add temporary features
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
- */
- createFeature: function(pixel) {
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- var geometry = new OpenLayers.Geometry.Point(
- lonlat.lon, lonlat.lat
- );
- this.point = new OpenLayers.Feature.Vector(geometry);
- this.callback("create", [this.point.geometry, this.point]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.point], {silent: true});
- },
-
- /**
- * APIMethod: deactivate
- * turn off the handler
- */
- deactivate: function() {
- if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- return false;
- }
- this.cancel();
- // If a layer's map property is set to null, it means that that layer
- // isn't added to the map. Since we ourself added the layer to the map
- // in activate(), we can assume that if this.layer.map is null it means
- // that the layer has been destroyed (as a result of map.destroy() for
- // example.
- if (this.layer.map != null) {
- this.destroyFeature(true);
- this.layer.destroy(false);
- }
- this.layer = null;
- return true;
- },
-
- /**
- * Method: destroyFeature
- * Destroy the temporary geometries
- *
- * Parameters:
- * force - {Boolean} Destroy even if persist is true.
- */
- destroyFeature: function(force) {
- if(this.layer && (force || !this.persist)) {
- this.layer.destroyFeatures();
- }
- this.point = null;
- },
-
- /**
- * Method: destroyPersistedFeature
- * Destroy the persisted feature.
- */
- destroyPersistedFeature: function() {
- var layer = this.layer;
- if(layer && layer.features.length > 1) {
- this.layer.features[0].destroy();
- }
- },
-
- /**
- * Method: finalize
- * Finish the geometry and call the "done" callback.
- *
- * Parameters:
- * cancel - {Boolean} Call cancel instead of done callback. Default
- * is false.
- */
- finalize: function(cancel) {
- var key = cancel ? "cancel" : "done";
- this.mouseDown = false;
- this.lastDown = null;
- this.lastUp = null;
- this.lastTouchPx = null;
- this.callback(key, [this.geometryClone()]);
- this.destroyFeature(cancel);
- },
-
- /**
- * APIMethod: cancel
- * Finish the geometry and call the "cancel" callback.
- */
- cancel: function() {
- this.finalize(true);
- },
-
- /**
- * Method: click
- * Handle clicks. Clicks are stopped from propagating to other listeners
- * on map.events or other dom elements.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- click: function(evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: dblclick
- * Handle double-clicks. Double-clicks are stopped from propagating to other
- * listeners on map.events or other dom elements.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- dblclick: function(evt) {
- OpenLayers.Event.stop(evt);
- return false;
- },
-
- /**
- * Method: modifyFeature
- * Modify the existing geometry given a pixel location.
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
- */
- modifyFeature: function(pixel) {
- if(!this.point) {
- this.createFeature(pixel);
- }
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- this.point.geometry.x = lonlat.lon;
- this.point.geometry.y = lonlat.lat;
- this.callback("modify", [this.point.geometry, this.point, false]);
- this.point.geometry.clearBounds();
- this.drawFeature();
- },
-
- /**
- * Method: drawFeature
- * Render features on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.Point>}
- */
- getGeometry: function() {
- var geometry = this.point && this.point.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
- }
- return geometry;
- },
-
- /**
- * Method: geometryClone
- * Return a clone of the relevant geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry>}
- */
- geometryClone: function() {
- var geom = this.getGeometry();
- return geom && geom.clone();
- },
-
- /**
- * Method: mousedown
- * Handle mousedown.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousedown: function(evt) {
- return this.down(evt);
- },
-
- /**
- * Method: touchstart
- * Handle touchstart.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- touchstart: function(evt) {
- this.startTouch();
- this.lastTouchPx = evt.xy;
- return this.down(evt);
- },
-
- /**
- * Method: mousemove
- * Handle mousemove.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mousemove: function(evt) {
- return this.move(evt);
- },
-
- /**
- * Method: touchmove
- * Handle touchmove.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- touchmove: function(evt) {
- this.lastTouchPx = evt.xy;
- return this.move(evt);
- },
-
- /**
- * Method: mouseup
- * Handle mouseup.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- mouseup: function(evt) {
- return this.up(evt);
- },
-
- /**
- * Method: touchend
- * Handle touchend.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- touchend: function(evt) {
- evt.xy = this.lastTouchPx;
- return this.up(evt);
- },
-
- /**
- * Method: down
- * Handle mousedown and touchstart. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- down: function(evt) {
- this.mouseDown = true;
- this.lastDown = evt.xy;
- if(!this.touch) { // no point displayed until up on touch devices
- this.modifyFeature(evt.xy);
- }
- this.stoppedDown = this.stopDown;
- return !this.stopDown;
- },
-
- /**
- * Method: move
- * Handle mousemove and touchmove. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- move: function (evt) {
- if(!this.touch // no point displayed until up on touch devices
- && (!this.mouseDown || this.stoppedDown)) {
- this.modifyFeature(evt.xy);
- }
- return true;
- },
-
- /**
- * Method: up
- * Handle mouseup and touchend. Send the latest point in the geometry to the control.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- up: function (evt) {
- this.mouseDown = false;
- this.stoppedDown = this.stopDown;
-
- // check keyboard modifiers
- if(!this.checkModifiers(evt)) {
- return true;
- }
- // ignore double-clicks
- if (this.lastUp && this.lastUp.equals(evt.xy)) {
- return true;
- }
- if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy,
- this.pixelTolerance)) {
- if (this.touch) {
- this.modifyFeature(evt.xy);
- }
- if(this.persist) {
- this.destroyPersistedFeature();
- }
- this.lastUp = evt.xy;
- this.finalize();
- return !this.stopUp;
- } else {
- return true;
- }
- },
-
- /**
- * Method: mouseout
- * Handle mouse out. For better user experience reset mouseDown
- * and stoppedDown when the mouse leaves the map viewport.
- *
- * Parameters:
- * evt - {Event} The browser event
- */
- mouseout: function(evt) {
- if(OpenLayers.Util.mouseLeft(evt, this.map.viewPortDiv)) {
- this.stoppedDown = this.stopDown;
- this.mouseDown = false;
- }
- },
-
- /**
- * Method: passesTolerance
- * Determine whether the event is within the optional pixel tolerance.
- *
- * Returns:
- * {Boolean} The event is within the pixel tolerance (if specified).
- */
- passesTolerance: function(pixel1, pixel2, tolerance) {
- var passes = true;
-
- if (tolerance != null && pixel1 && pixel2) {
- var dist = pixel1.distanceTo(pixel2);
- if (dist > tolerance) {
- passes = false;
- }
- }
- return passes;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Point"
-});
-/* ======================================================================
- OpenLayers/Handler/Path.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler/Point.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/LineString.js
- */
-
-/**
- * Class: OpenLayers.Handler.Path
- * Handler to draw a path on the map. Path is displayed on mouse down,
- * moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler.Point>
- */
-OpenLayers.Handler.Path = OpenLayers.Class(OpenLayers.Handler.Point, {
-
- /**
- * Property: line
- * {<OpenLayers.Feature.Vector>}
- */
- line: null,
-
- /**
- * APIProperty: maxVertices
- * {Number} The maximum number of vertices which can be drawn by this
- * handler. When the number of vertices reaches maxVertices, the
- * geometry is automatically finalized. Default is null.
- */
- maxVertices: null,
-
- /**
- * Property: doubleTouchTolerance
- * {Number} Maximum number of pixels between two touches for
- * the gesture to be considered a "finalize feature" action.
- * Default is 20.
- */
- doubleTouchTolerance: 20,
-
- /**
- * Property: freehand
- * {Boolean} In freehand mode, the handler starts the path on mouse down,
- * adds a point for every mouse move, and finishes the path on mouse up.
- * Outside of freehand mode, a point is added to the path on every mouse
- * click and double-click finishes the path.
- */
- freehand: false,
-
- /**
- * Property: freehandToggle
- * {String} If set, freehandToggle is checked on mouse events and will set
- * the freehand mode to the opposite of this.freehand. To disallow
- * toggling between freehand and non-freehand mode, set freehandToggle to
- * null. Acceptable toggle values are 'shiftKey', 'ctrlKey', and 'altKey'.
- */
- freehandToggle: 'shiftKey',
-
- /**
- * Property: timerId
- * {Integer} The timer used to test the double touch.
- */
- timerId: null,
-
- /**
- * Property: redoStack
- * {Array} Stack containing points removed with <undo>.
- */
- redoStack: null,
-
- /**
- * Constructor: OpenLayers.Handler.Path
- * Create a new path hander
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * point - Called as each point is added. Receives the new point geometry.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the linestring geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
-
- /**
- * Method: createFeature
- * Add temporary geometries
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
- * feature.
- */
- createFeature: function(pixel) {
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- var geometry = new OpenLayers.Geometry.Point(
- lonlat.lon, lonlat.lat
- );
- this.point = new OpenLayers.Feature.Vector(geometry);
- this.line = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.LineString([this.point.geometry])
- );
- this.callback("create", [this.point.geometry, this.getSketch()]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.line, this.point], {silent: true});
- },
-
- /**
- * Method: destroyFeature
- * Destroy temporary geometries
- *
- * Parameters:
- * force - {Boolean} Destroy even if persist is true.
- */
- destroyFeature: function(force) {
- OpenLayers.Handler.Point.prototype.destroyFeature.call(
- this, force);
- this.line = null;
- },
-
- /**
- * Method: destroyPersistedFeature
- * Destroy the persisted feature.
- */
- destroyPersistedFeature: function() {
- var layer = this.layer;
- if(layer && layer.features.length > 2) {
- this.layer.features[0].destroy();
- }
- },
-
- /**
- * Method: removePoint
- * Destroy the temporary point.
- */
- removePoint: function() {
- if(this.point) {
- this.layer.removeFeatures([this.point]);
- }
- },
-
- /**
- * Method: addPoint
- * Add point to geometry. Send the point index to override
- * the behavior of LinearRing that disregards adding duplicate points.
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
- */
- addPoint: function(pixel) {
- this.layer.removeFeatures([this.point]);
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- this.point = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
- );
- this.line.geometry.addComponent(
- this.point.geometry, this.line.geometry.components.length
- );
- this.layer.addFeatures([this.point]);
- this.callback("point", [this.point.geometry, this.getGeometry()]);
- this.callback("modify", [this.point.geometry, this.getSketch()]);
- this.drawFeature();
- delete this.redoStack;
- },
-
- /**
- * Method: insertXY
- * Insert a point in the current sketch given x & y coordinates. The new
- * point is inserted immediately before the most recently drawn point.
- *
- * Parameters:
- * x - {Number} The x-coordinate of the point.
- * y - {Number} The y-coordinate of the point.
- */
- insertXY: function(x, y) {
- this.line.geometry.addComponent(
- new OpenLayers.Geometry.Point(x, y),
- this.getCurrentPointIndex()
- );
- this.drawFeature();
- delete this.redoStack;
- },
-
- /**
- * Method: insertDeltaXY
- * Insert a point given offsets from the previously inserted point.
- *
- * Parameters:
- * dx - {Number} The x-coordinate offset of the point.
- * dy - {Number} The y-coordinate offset of the point.
- */
- insertDeltaXY: function(dx, dy) {
- var previousIndex = this.getCurrentPointIndex() - 1;
- var p0 = this.line.geometry.components[previousIndex];
- if (p0 && !isNaN(p0.x) && !isNaN(p0.y)) {
- this.insertXY(p0.x + dx, p0.y + dy);
- }
- },
-
- /**
- * Method: insertDirectionLength
- * Insert a point in the current sketch given a direction and a length.
- *
- * Parameters:
- * direction - {Number} Degrees clockwise from the positive x-axis.
- * length - {Number} Distance from the previously drawn point.
- */
- insertDirectionLength: function(direction, length) {
- direction *= Math.PI / 180;
- var dx = length * Math.cos(direction);
- var dy = length * Math.sin(direction);
- this.insertDeltaXY(dx, dy);
- },
-
- /**
- * Method: insertDeflectionLength
- * Insert a point in the current sketch given a deflection and a length.
- * The deflection should be degrees clockwise from the previously
- * digitized segment.
- *
- * Parameters:
- * deflection - {Number} Degrees clockwise from the previous segment.
- * length - {Number} Distance from the previously drawn point.
- */
- insertDeflectionLength: function(deflection, length) {
- var previousIndex = this.getCurrentPointIndex() - 1;
- if (previousIndex > 0) {
- var p1 = this.line.geometry.components[previousIndex];
- var p0 = this.line.geometry.components[previousIndex-1];
- var theta = Math.atan2(p1.y - p0.y, p1.x - p0.x);
- this.insertDirectionLength(
- (theta * 180 / Math.PI) + deflection, length
- );
- }
- },
-
- /**
- * Method: getCurrentPointIndex
- *
- * Returns:
- * {Number} The index of the most recently drawn point.
- */
- getCurrentPointIndex: function() {
- return this.line.geometry.components.length - 1;
- },
-
-
- /**
- * Method: undo
- * Remove the most recently added point in the sketch geometry.
- *
- * Returns:
- * {Boolean} A point was removed.
- */
- undo: function() {
- var geometry = this.line.geometry;
- var components = geometry.components;
- var index = this.getCurrentPointIndex() - 1;
- var target = components[index];
- var undone = geometry.removeComponent(target);
- if (undone) {
- // On touch devices, set the current ("mouse location") point to
- // match the last digitized point.
- if (this.touch && index > 0) {
- components = geometry.components; // safety
- var lastpt = components[index - 1];
- var curptidx = this.getCurrentPointIndex();
- var curpt = components[curptidx];
- curpt.x = lastpt.x;
- curpt.y = lastpt.y;
- }
- if (!this.redoStack) {
- this.redoStack = [];
- }
- this.redoStack.push(target);
- this.drawFeature();
- }
- return undone;
- },
-
- /**
- * Method: redo
- * Reinsert the most recently removed point resulting from an <undo> call.
- * The undo stack is deleted whenever a point is added by other means.
- *
- * Returns:
- * {Boolean} A point was added.
- */
- redo: function() {
- var target = this.redoStack && this.redoStack.pop();
- if (target) {
- this.line.geometry.addComponent(target, this.getCurrentPointIndex());
- this.drawFeature();
- }
- return !!target;
- },
-
- /**
- * Method: freehandMode
- * Determine whether to behave in freehand mode or not.
- *
- * Returns:
- * {Boolean}
- */
- freehandMode: function(evt) {
- return (this.freehandToggle && evt[this.freehandToggle]) ?
- !this.freehand : this.freehand;
- },
-
- /**
- * Method: modifyFeature
- * Modify the existing geometry given the new point
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The updated pixel location for the latest
- * point.
- * drawing - {Boolean} Indicate if we're currently drawing.
- */
- modifyFeature: function(pixel, drawing) {
- if(!this.line) {
- this.createFeature(pixel);
- }
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- this.point.geometry.x = lonlat.lon;
- this.point.geometry.y = lonlat.lat;
- this.callback("modify", [this.point.geometry, this.getSketch(), drawing]);
- this.point.geometry.clearBounds();
- this.drawFeature();
- },
-
- /**
- * Method: drawFeature
- * Render geometries on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.line, this.style);
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getSketch
- * Return the sketch feature.
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>}
- */
- getSketch: function() {
- return this.line;
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.LineString>}
- */
- getGeometry: function() {
- var geometry = this.line && this.line.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiLineString([geometry]);
- }
- return geometry;
- },
-
- /**
- * method: touchstart
- * handle touchstart.
- *
- * parameters:
- * evt - {event} the browser event
- *
- * returns:
- * {boolean} allow event propagation
- */
- touchstart: function(evt) {
- if (this.timerId &&
- this.passesTolerance(this.lastTouchPx, evt.xy,
- this.doubleTouchTolerance)) {
- // double-tap, finalize the geometry
- this.finishGeometry();
- window.clearTimeout(this.timerId);
- this.timerId = null;
- return false;
- } else {
- if (this.timerId) {
- window.clearTimeout(this.timerId);
- this.timerId = null;
- }
- this.timerId = window.setTimeout(
- OpenLayers.Function.bind(function() {
- this.timerId = null;
- }, this), 300);
- return OpenLayers.Handler.Point.prototype.touchstart.call(this, evt);
- }
- },
-
- /**
- * Method: down
- * Handle mousedown and touchstart. Add a new point to the geometry and
- * render it. Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- down: function(evt) {
- var stopDown = this.stopDown;
- if(this.freehandMode(evt)) {
- stopDown = true;
- if (this.touch) {
- this.modifyFeature(evt.xy, !!this.lastUp);
- OpenLayers.Event.stop(evt);
- }
- }
- if (!this.touch && (!this.lastDown ||
- !this.passesTolerance(this.lastDown, evt.xy,
- this.pixelTolerance))) {
- this.modifyFeature(evt.xy, !!this.lastUp);
- }
- this.mouseDown = true;
- this.lastDown = evt.xy;
- this.stoppedDown = stopDown;
- return !stopDown;
- },
-
- /**
- * Method: move
- * Handle mousemove and touchmove. Adjust the geometry and redraw.
- * Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- move: function (evt) {
- if(this.stoppedDown && this.freehandMode(evt)) {
- if(this.persist) {
- this.destroyPersistedFeature();
- }
- if(this.maxVertices && this.line &&
- this.line.geometry.components.length === this.maxVertices) {
- this.removePoint();
- this.finalize();
- } else {
- this.addPoint(evt.xy);
- }
- return false;
- }
- if (!this.touch && (!this.mouseDown || this.stoppedDown)) {
- this.modifyFeature(evt.xy, !!this.lastUp);
- }
- return true;
- },
-
- /**
- * Method: up
- * Handle mouseup and touchend. Send the latest point in the geometry to
- * the control. Return determines whether to propagate the event on the map.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- up: function (evt) {
- if (this.mouseDown && (!this.lastUp || !this.lastUp.equals(evt.xy))) {
- if(this.stoppedDown && this.freehandMode(evt)) {
- if (this.persist) {
- this.destroyPersistedFeature();
- }
- this.removePoint();
- this.finalize();
- } else {
- if (this.passesTolerance(this.lastDown, evt.xy,
- this.pixelTolerance)) {
- if (this.touch) {
- this.modifyFeature(evt.xy);
- }
- if(this.lastUp == null && this.persist) {
- this.destroyPersistedFeature();
- }
- this.addPoint(evt.xy);
- this.lastUp = evt.xy;
- if(this.line.geometry.components.length === this.maxVertices + 1) {
- this.finishGeometry();
- }
- }
- }
- }
- this.stoppedDown = this.stopDown;
- this.mouseDown = false;
- return !this.stopUp;
- },
-
- /**
- * APIMethod: finishGeometry
- * Finish the geometry and send it back to the control.
- */
- finishGeometry: function() {
- var index = this.line.geometry.components.length - 1;
- this.line.geometry.removeComponent(this.line.geometry.components[index]);
- this.removePoint();
- this.finalize();
- },
-
- /**
- * Method: dblclick
- * Handle double-clicks.
- *
- * Parameters:
- * evt - {Event} The browser event
- *
- * Returns:
- * {Boolean} Allow event propagation
- */
- dblclick: function(evt) {
- if(!this.freehandMode(evt)) {
- this.finishGeometry();
- }
- return false;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Path"
-});
-/* ======================================================================
- OpenLayers/Control/Attribution.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- */
-
-/**
- * Class: OpenLayers.Control.Attribution
- * The attribution control adds attribution from layers to the map display.
- * It uses 'attribution' property of each layer.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Attribution =
- OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * APIProperty: separator
- * {String} String used to separate layers.
- */
- separator: ", ",
-
- /**
- * APIProperty: template
- * {String} Template for the attribution. This has to include the substring
- * "${layers}", which will be replaced by the layer specific
- * attributions, separated by <separator>. The default is "${layers}".
- */
- template: "${layers}",
-
- /**
- * Constructor: OpenLayers.Control.Attribution
- *
- * Parameters:
- * options - {Object} Options for control.
- */
-
- /**
- * Method: destroy
- * Destroy control.
- */
- destroy: function() {
- this.map.events.un({
- "removelayer": this.updateAttribution,
- "addlayer": this.updateAttribution,
- "changelayer": this.updateAttribution,
- "changebaselayer": this.updateAttribution,
- scope: this
- });
-
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: draw
- * Initialize control.
- *
- * Returns:
- * {DOMElement} A reference to the DIV DOMElement containing the control
- */
- draw: function() {
- OpenLayers.Control.prototype.draw.apply(this, arguments);
-
- this.map.events.on({
- 'changebaselayer': this.updateAttribution,
- 'changelayer': this.updateAttribution,
- 'addlayer': this.updateAttribution,
- 'removelayer': this.updateAttribution,
- scope: this
- });
- this.updateAttribution();
-
- return this.div;
- },
-
- /**
- * Method: updateAttribution
- * Update attribution string.
- */
- updateAttribution: function() {
- var attributions = [];
- if (this.map && this.map.layers) {
- for(var i=0, len=this.map.layers.length; i<len; i++) {
- var layer = this.map.layers[i];
- if (layer.attribution && layer.getVisibility()) {
- // add attribution only if attribution text is unique
- if (OpenLayers.Util.indexOf(
- attributions, layer.attribution) === -1) {
- attributions.push( layer.attribution );
- }
- }
- }
- this.div.innerHTML = OpenLayers.String.format(this.template, {
- layers: attributions.join(this.separator)
- });
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.Attribution"
-});
-/* ======================================================================
- OpenLayers/Kinetic.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/BaseTypes/Class.js
- * @requires OpenLayers/Animation.js
- */
-
-OpenLayers.Kinetic = OpenLayers.Class({
-
- /**
- * Property: threshold
- * In most cases changing the threshold isn't needed.
- * In px/ms, default to 0.
- */
- threshold: 0,
-
- /**
- * Property: deceleration
- * {Float} the deseleration in px/ms², default to 0.0035.
- */
- deceleration: 0.0035,
-
- /**
- * Property: nbPoints
- * {Integer} the number of points we use to calculate the kinetic
- * initial values.
- */
- nbPoints: 100,
-
- /**
- * Property: delay
- * {Float} time to consider to calculate the kinetic initial values.
- * In ms, default to 200.
- */
- delay: 200,
-
- /**
- * Property: points
- * List of points use to calculate the kinetic initial values.
- */
- points: undefined,
-
- /**
- * Property: timerId
- * ID of the timer.
- */
- timerId: undefined,
-
- /**
- * Constructor: OpenLayers.Kinetic
- *
- * Parameters:
- * options - {Object}
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- },
-
- /**
- * Method: begin
- * Begins the dragging.
- */
- begin: function() {
- OpenLayers.Animation.stop(this.timerId);
- this.timerId = undefined;
- this.points = [];
- },
-
- /**
- * Method: update
- * Updates during the dragging.
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} The new position.
- */
- update: function(xy) {
- this.points.unshift({xy: xy, tick: new Date().getTime()});
- if (this.points.length > this.nbPoints) {
- this.points.pop();
- }
- },
-
- /**
- * Method: end
- * Ends the dragging, start the kinetic.
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} The last position.
- *
- * Returns:
- * {Object} An object with two properties: "speed", and "theta". The
- * "speed" and "theta" values are to be passed to the move
- * function when starting the animation.
- */
- end: function(xy) {
- var last, now = new Date().getTime();
- for (var i = 0, l = this.points.length, point; i < l; i++) {
- point = this.points[i];
- if (now - point.tick > this.delay) {
- break;
- }
- last = point;
- }
- if (!last) {
- return;
- }
- var time = new Date().getTime() - last.tick;
- var dist = Math.sqrt(Math.pow(xy.x - last.xy.x, 2) +
- Math.pow(xy.y - last.xy.y, 2));
- var speed = dist / time;
- if (speed == 0 || speed < this.threshold) {
- return;
- }
- var theta = Math.asin((xy.y - last.xy.y) / dist);
- if (last.xy.x <= xy.x) {
- theta = Math.PI - theta;
- }
- return {speed: speed, theta: theta};
- },
-
- /**
- * Method: move
- * Launch the kinetic move pan.
- *
- * Parameters:
- * info - {Object} An object with two properties, "speed", and "theta".
- * These values are those returned from the "end" call.
- * callback - {Function} Function called on every step of the animation,
- * receives x, y (values to pan), end (is the last point).
- */
- move: function(info, callback) {
- var v0 = info.speed;
- var fx = Math.cos(info.theta);
- var fy = -Math.sin(info.theta);
-
- var initialTime = new Date().getTime();
-
- var lastX = 0;
- var lastY = 0;
-
- var timerCallback = function() {
- if (this.timerId == null) {
- return;
- }
-
- var t = new Date().getTime() - initialTime;
-
- var p = (-this.deceleration * Math.pow(t, 2)) / 2.0 + v0 * t;
- var x = p * fx;
- var y = p * fy;
-
- var args = {};
- args.end = false;
- var v = -this.deceleration * t + v0;
-
- if (v <= 0) {
- OpenLayers.Animation.stop(this.timerId);
- this.timerId = null;
- args.end = true;
- }
-
- args.x = x - lastX;
- args.y = y - lastY;
- lastX = x;
- lastY = y;
- callback(args.x, args.y, args.end);
- };
-
- this.timerId = OpenLayers.Animation.start(
- OpenLayers.Function.bind(timerCallback, this)
- );
- },
-
- CLASS_NAME: "OpenLayers.Kinetic"
-});
-/* ======================================================================
- OpenLayers/Layer/WMS.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Layer/Grid.js
- */
-
-/**
- * Class: OpenLayers.Layer.WMS
- * Instances of OpenLayers.Layer.WMS are used to display data from OGC Web
- * Mapping Services. Create a new WMS layer with the <OpenLayers.Layer.WMS>
- * constructor.
- *
- * Inherits from:
- * - <OpenLayers.Layer.Grid>
- */
-OpenLayers.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.Grid, {
-
- /**
- * Constant: DEFAULT_PARAMS
- * {Object} Hashtable of default parameter key/value pairs
- */
- DEFAULT_PARAMS: { service: "WMS",
- version: "1.1.1",
- request: "GetMap",
- styles: "",
- format: "image/jpeg"
- },
-
- /**
- * APIProperty: isBaseLayer
- * {Boolean} Default is true for WMS layer
- */
- isBaseLayer: true,
-
- /**
- * APIProperty: encodeBBOX
- * {Boolean} Should the BBOX commas be encoded? The WMS spec says 'no',
- * but some services want it that way. Default false.
- */
- encodeBBOX: false,
-
- /**
- * APIProperty: noMagic
- * {Boolean} If true, the image format will not be automagicaly switched
- * from image/jpeg to image/png or image/gif when using
- * TRANSPARENT=TRUE. Also isBaseLayer will not changed by the
- * constructor. Default false.
- */
- noMagic: false,
-
- /**
- * Property: yx
- * {Object} Keys in this object are EPSG codes for which the axis order
- * is to be reversed (yx instead of xy, LatLon instead of LonLat), with
- * true as value. This is only relevant for WMS versions >= 1.3.0, and
- * only if yx is not set in <OpenLayers.Projection.defaults> for the
- * used projection.
- */
- yx: {},
-
- /**
- * Constructor: OpenLayers.Layer.WMS
- * Create a new WMS layer object
- *
- * Examples:
- *
- * The code below creates a simple WMS layer using the image/jpeg format.
- * (code)
- * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
- * "http://wms.jpl.nasa.gov/wms.cgi",
- * {layers: "modis,global_mosaic"});
- * (end)
- * Note the 3rd argument (params). Properties added to this object will be
- * added to the WMS GetMap requests used for this layer's tiles. The only
- * mandatory parameter is "layers". Other common WMS params include
- * "transparent", "styles" and "format". Note that the "srs" param will
- * always be ignored. Instead, it will be derived from the baseLayer's or
- * map's projection.
- *
- * The code below creates a transparent WMS layer with additional options.
- * (code)
- * var wms = new OpenLayers.Layer.WMS("NASA Global Mosaic",
- * "http://wms.jpl.nasa.gov/wms.cgi",
- * {
- * layers: "modis,global_mosaic",
- * transparent: true
- * }, {
- * opacity: 0.5,
- * singleTile: true
- * });
- * (end)
- * Note that by default, a WMS layer is configured as baseLayer. Setting
- * the "transparent" param to true will apply some magic (see <noMagic>).
- * The default image format changes from image/jpeg to image/png, and the
- * layer is not configured as baseLayer.
- *
- * Parameters:
- * name - {String} A name for the layer
- * url - {String} Base url for the WMS
- * (e.g. http://wms.jpl.nasa.gov/wms.cgi)
- * params - {Object} An object with key/value pairs representing the
- * GetMap query string parameters and parameter values.
- * options - {Object} Hashtable of extra options to tag onto the layer.
- * These options include all properties listed above, plus the ones
- * inherited from superclasses.
- */
- initialize: function(name, url, params, options) {
- var newArguments = [];
- //uppercase params
- params = OpenLayers.Util.upperCaseObject(params);
- if (parseFloat(params.VERSION) >= 1.3 && !params.EXCEPTIONS) {
- params.EXCEPTIONS = "INIMAGE";
- }
- newArguments.push(name, url, params, options);
- OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
- OpenLayers.Util.applyDefaults(
- this.params,
- OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
- );
-
-
- //layer is transparent
- if (!this.noMagic && this.params.TRANSPARENT &&
- this.params.TRANSPARENT.toString().toLowerCase() == "true") {
-
- // unless explicitly set in options, make layer an overlay
- if ( (options == null) || (!options.isBaseLayer) ) {
- this.isBaseLayer = false;
- }
-
- // jpegs can never be transparent, so intelligently switch the
- // format, depending on the browser's capabilities
- if (this.params.FORMAT == "image/jpeg") {
- this.params.FORMAT = OpenLayers.Util.alphaHack() ? "image/gif"
- : "image/png";
- }
- }
-
- },
-
- /**
- * Method: clone
- * Create a clone of this layer
- *
- * Returns:
- * {<OpenLayers.Layer.WMS>} An exact clone of this layer
- */
- clone: function (obj) {
-
- if (obj == null) {
- obj = new OpenLayers.Layer.WMS(this.name,
- this.url,
- this.params,
- this.getOptions());
- }
-
- //get all additions from superclasses
- obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
-
- // copy/set any non-init, non-simple values here
-
- return obj;
- },
-
- /**
- * APIMethod: reverseAxisOrder
- * Returns true if the axis order is reversed for the WMS version and
- * projection of the layer.
- *
- * Returns:
- * {Boolean} true if the axis order is reversed, false otherwise.
- */
- reverseAxisOrder: function() {
- var projCode = this.projection.getCode();
- return parseFloat(this.params.VERSION) >= 1.3 &&
- !!(this.yx[projCode] || (OpenLayers.Projection.defaults[projCode] &&
- OpenLayers.Projection.defaults[projCode].yx));
- },
-
- /**
- * Method: getURL
- * Return a GetMap query string for this layer
- *
- * Parameters:
- * bounds - {<OpenLayers.Bounds>} A bounds representing the bbox for the
- * request.
- *
- * Returns:
- * {String} A string with the layer's url and parameters and also the
- * passed-in bounds and appropriate tile size specified as
- * parameters.
- */
- getURL: function (bounds) {
- bounds = this.adjustBounds(bounds);
-
- var imageSize = this.getImageSize();
- var newParams = {};
- // WMS 1.3 introduced axis order
- var reverseAxisOrder = this.reverseAxisOrder();
- newParams.BBOX = this.encodeBBOX ?
- bounds.toBBOX(null, reverseAxisOrder) :
- bounds.toArray(reverseAxisOrder);
- newParams.WIDTH = imageSize.w;
- newParams.HEIGHT = imageSize.h;
- var requestString = this.getFullRequestString(newParams);
- return requestString;
- },
-
- /**
- * APIMethod: mergeNewParams
- * Catch changeParams and uppercase the new params to be merged in
- * before calling changeParams on the super class.
- *
- * Once params have been changed, the tiles will be reloaded with
- * the new parameters.
- *
- * Parameters:
- * newParams - {Object} Hashtable of new params to use
- */
- mergeNewParams:function(newParams) {
- var upperParams = OpenLayers.Util.upperCaseObject(newParams);
- var newArguments = [upperParams];
- return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,
- newArguments);
- },
-
- /**
- * APIMethod: getFullRequestString
- * Combine the layer's url with its params and these newParams.
- *
- * Add the SRS parameter from projection -- this is probably
- * more eloquently done via a setProjection() method, but this
- * works for now and always.
- *
- * Parameters:
- * newParams - {Object}
- * altUrl - {String} Use this as the url instead of the layer's url
- *
- * Returns:
- * {String}
- */
- getFullRequestString:function(newParams, altUrl) {
- var mapProjection = this.map.getProjectionObject();
- var projectionCode = this.projection && this.projection.equals(mapProjection) ?
- this.projection.getCode() :
- mapProjection.getCode();
- var value = (projectionCode == "none") ? null : projectionCode;
- if (parseFloat(this.params.VERSION) >= 1.3) {
- this.params.CRS = value;
- } else {
- this.params.SRS = value;
- }
-
- if (typeof this.params.TRANSPARENT == "boolean") {
- newParams.TRANSPARENT = this.params.TRANSPARENT ? "TRUE" : "FALSE";
- }
-
- return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
- this, arguments);
- },
-
- CLASS_NAME: "OpenLayers.Layer.WMS"
-});
-/* ======================================================================
- OpenLayers/Renderer/SVG.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Renderer/Elements.js
- */
-
-/**
- * Class: OpenLayers.Renderer.SVG
- *
- * Inherits:
- * - <OpenLayers.Renderer.Elements>
- */
-OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
-
- /**
- * Property: xmlns
- * {String}
- */
- xmlns: "http://www.w3.org/2000/svg",
-
- /**
- * Property: xlinkns
- * {String}
- */
- xlinkns: "http://www.w3.org/1999/xlink",
-
- /**
- * Constant: MAX_PIXEL
- * {Integer} Firefox has a limitation where values larger or smaller than
- * about 15000 in an SVG document lock the browser up. This
- * works around it.
- */
- MAX_PIXEL: 15000,
-
- /**
- * Property: translationParameters
- * {Object} Hash with "x" and "y" properties
- */
- translationParameters: null,
-
- /**
- * Property: symbolMetrics
- * {Object} Cache for symbol metrics according to their svg coordinate
- * space. This is an object keyed by the symbol's id, and values are
- * an array of [width, centerX, centerY].
- */
- symbolMetrics: null,
-
- /**
- * Constructor: OpenLayers.Renderer.SVG
- *
- * Parameters:
- * containerID - {String}
- */
- initialize: function(containerID) {
- if (!this.supported()) {
- return;
- }
- OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
- arguments);
- this.translationParameters = {x: 0, y: 0};
-
- this.symbolMetrics = {};
- },
-
- /**
- * APIMethod: supported
- *
- * Returns:
- * {Boolean} Whether or not the browser supports the SVG renderer
- */
- supported: function() {
- var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
- return (document.implementation &&
- (document.implementation.hasFeature("org.w3c.svg", "1.0") ||
- document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
- document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
- },
-
- /**
- * Method: inValidRange
- * See #669 for more information
- *
- * Parameters:
- * x - {Integer}
- * y - {Integer}
- * xyOnly - {Boolean} whether or not to just check for x and y, which means
- * to not take the current translation parameters into account if true.
- *
- * Returns:
- * {Boolean} Whether or not the 'x' and 'y' coordinates are in the
- * valid range.
- */
- inValidRange: function(x, y, xyOnly) {
- var left = x + (xyOnly ? 0 : this.translationParameters.x);
- var top = y + (xyOnly ? 0 : this.translationParameters.y);
- return (left >= -this.MAX_PIXEL && left <= this.MAX_PIXEL &&
- top >= -this.MAX_PIXEL && top <= this.MAX_PIXEL);
- },
-
- /**
- * Method: setExtent
- *
- * Parameters:
- * extent - {<OpenLayers.Bounds>}
- * resolutionChanged - {Boolean}
- *
- * Returns:
- * {Boolean} true to notify the layer that the new extent does not exceed
- * the coordinate range, and the features will not need to be redrawn.
- * False otherwise.
- */
- setExtent: function(extent, resolutionChanged) {
- var coordSysUnchanged = OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, arguments);
-
- var resolution = this.getResolution(),
- left = -extent.left / resolution,
- top = extent.top / resolution;
-
- // If the resolution has changed, start over changing the corner, because
- // the features will redraw.
- if (resolutionChanged) {
- this.left = left;
- this.top = top;
- // Set the viewbox
- var extentString = "0 0 " + this.size.w + " " + this.size.h;
-
- this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
- this.translate(this.xOffset, 0);
- return true;
- } else {
- var inRange = this.translate(left - this.left + this.xOffset, top - this.top);
- if (!inRange) {
- // recenter the coordinate system
- this.setExtent(extent, true);
- }
- return coordSysUnchanged && inRange;
- }
- },
-
- /**
- * Method: translate
- * Transforms the SVG coordinate system
- *
- * Parameters:
- * x - {Float}
- * y - {Float}
- *
- * Returns:
- * {Boolean} true if the translation parameters are in the valid coordinates
- * range, false otherwise.
- */
- translate: function(x, y) {
- if (!this.inValidRange(x, y, true)) {
- return false;
- } else {
- var transformString = "";
- if (x || y) {
- transformString = "translate(" + x + "," + y + ")";
- }
- this.root.setAttributeNS(null, "transform", transformString);
- this.translationParameters = {x: x, y: y};
- return true;
- }
- },
-
- /**
- * Method: setSize
- * Sets the size of the drawing surface.
- *
- * Parameters:
- * size - {<OpenLayers.Size>} The size of the drawing surface
- */
- setSize: function(size) {
- OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
-
- this.rendererRoot.setAttributeNS(null, "width", this.size.w);
- this.rendererRoot.setAttributeNS(null, "height", this.size.h);
- },
-
- /**
- * Method: getNodeType
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- * style - {Object}
- *
- * Returns:
- * {String} The corresponding node type for the specified geometry
- */
- getNodeType: function(geometry, style) {
- var nodeType = null;
- switch (geometry.CLASS_NAME) {
- case "OpenLayers.Geometry.Point":
- if (style.externalGraphic) {
- nodeType = "image";
- } else if (this.isComplexSymbol(style.graphicName)) {
- nodeType = "svg";
- } else {
- nodeType = "circle";
- }
- break;
- case "OpenLayers.Geometry.Rectangle":
- nodeType = "rect";
- break;
- case "OpenLayers.Geometry.LineString":
- nodeType = "polyline";
- break;
- case "OpenLayers.Geometry.LinearRing":
- nodeType = "polygon";
- break;
- case "OpenLayers.Geometry.Polygon":
- case "OpenLayers.Geometry.Curve":
- nodeType = "path";
- break;
- default:
- break;
- }
- return nodeType;
- },
-
- /**
- * Method: setStyle
- * Use to set all the style attributes to a SVG node.
- *
- * Takes care to adjust stroke width and point radius to be
- * resolution-relative
- *
- * Parameters:
- * node - {SVGDomElement} An SVG element to decorate
- * style - {Object}
- * options - {Object} Currently supported options include
- * 'isFilled' {Boolean} and
- * 'isStroked' {Boolean}
- */
- setStyle: function(node, style, options) {
- style = style || node._style;
- options = options || node._options;
-
- var title = style.title || style.graphicTitle;
- if (title) {
- node.setAttributeNS(null, "title", title);
- //Standards-conformant SVG
- // Prevent duplicate nodes. See issue https://github.com/openlayers/openlayers/issues/92
- var titleNode = node.getElementsByTagName("title");
- if (titleNode.length > 0) {
- titleNode[0].firstChild.textContent = title;
- } else {
- var label = this.nodeFactory(null, "title");
- label.textContent = title;
- node.appendChild(label);
- }
- }
-
- var r = parseFloat(node.getAttributeNS(null, "r"));
- var widthFactor = 1;
- var pos;
- if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
- node.style.visibility = "";
- if (style.graphic === false) {
- node.style.visibility = "hidden";
- } else if (style.externalGraphic) {
- pos = this.getPosition(node);
- if (style.graphicWidth && style.graphicHeight) {
- node.setAttributeNS(null, "preserveAspectRatio", "none");
- }
- var width = style.graphicWidth || style.graphicHeight;
- var height = style.graphicHeight || style.graphicWidth;
- width = width ? width : style.pointRadius*2;
- height = height ? height : style.pointRadius*2;
- var xOffset = (style.graphicXOffset != undefined) ?
- style.graphicXOffset : -(0.5 * width);
- var yOffset = (style.graphicYOffset != undefined) ?
- style.graphicYOffset : -(0.5 * height);
-
- var opacity = style.graphicOpacity || style.fillOpacity;
-
- node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
- node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
- node.setAttributeNS(null, "width", width);
- node.setAttributeNS(null, "height", height);
- node.setAttributeNS(this.xlinkns, "xlink:href", style.externalGraphic);
- node.setAttributeNS(null, "style", "opacity: "+opacity);
- node.onclick = OpenLayers.Event.preventDefault;
- } else if (this.isComplexSymbol(style.graphicName)) {
- // the symbol viewBox is three times as large as the symbol
- var offset = style.pointRadius * 3;
- var size = offset * 2;
- var src = this.importSymbol(style.graphicName);
- pos = this.getPosition(node);
- widthFactor = this.symbolMetrics[src.id][0] * 3 / size;
-
- // remove the node from the dom before we modify it. This
- // prevents various rendering issues in Safari and FF
- var parent = node.parentNode;
- var nextSibling = node.nextSibling;
- if(parent) {
- parent.removeChild(node);
- }
-
- // The more appropriate way to implement this would be use/defs,
- // but due to various issues in several browsers, it is safer to
- // copy the symbols instead of referencing them.
- // See e.g. ticket http://trac.osgeo.org/openlayers/ticket/2985
- // and this email thread
- // http://osgeo-org.1803224.n2.nabble.com/Select-Control-Ctrl-click-on-Feature-with-a-graphicName-opens-new-browser-window-tc5846039.html
- node.firstChild && node.removeChild(node.firstChild);
- node.appendChild(src.firstChild.cloneNode(true));
- node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
-
- node.setAttributeNS(null, "width", size);
- node.setAttributeNS(null, "height", size);
- node.setAttributeNS(null, "x", pos.x - offset);
- node.setAttributeNS(null, "y", pos.y - offset);
-
- // now that the node has all its new properties, insert it
- // back into the dom where it was
- if(nextSibling) {
- parent.insertBefore(node, nextSibling);
- } else if(parent) {
- parent.appendChild(node);
- }
- } else {
- node.setAttributeNS(null, "r", style.pointRadius);
- }
-
- var rotation = style.rotation;
-
- if ((rotation !== undefined || node._rotation !== undefined) && pos) {
- node._rotation = rotation;
- rotation |= 0;
- if (node.nodeName !== "svg") {
- node.setAttributeNS(null, "transform",
- "rotate(" + rotation + " " + pos.x + " " +
- pos.y + ")");
- } else {
- var metrics = this.symbolMetrics[src.id];
- node.firstChild.setAttributeNS(null, "transform", "rotate("
- + rotation + " "
- + metrics[1] + " "
- + metrics[2] + ")");
- }
- }
- }
-
- if (options.isFilled) {
- node.setAttributeNS(null, "fill", style.fillColor);
- node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
- } else {
- node.setAttributeNS(null, "fill", "none");
- }
-
- if (options.isStroked) {
- node.setAttributeNS(null, "stroke", style.strokeColor);
- node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
- node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
- node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
- // Hard-coded linejoin for now, to make it look the same as in VML.
- // There is no strokeLinejoin property yet for symbolizers.
- node.setAttributeNS(null, "stroke-linejoin", "round");
- style.strokeDashstyle && node.setAttributeNS(null,
- "stroke-dasharray", this.dashStyle(style, widthFactor));
- } else {
- node.setAttributeNS(null, "stroke", "none");
- }
-
- if (style.pointerEvents) {
- node.setAttributeNS(null, "pointer-events", style.pointerEvents);
- }
-
- if (style.cursor != null) {
- node.setAttributeNS(null, "cursor", style.cursor);
- }
-
- return node;
- },
-
- /**
- * Method: dashStyle
- *
- * Parameters:
- * style - {Object}
- * widthFactor - {Number}
- *
- * Returns:
- * {String} A SVG compliant 'stroke-dasharray' value
- */
- dashStyle: function(style, widthFactor) {
- var w = style.strokeWidth * widthFactor;
- var str = style.strokeDashstyle;
- switch (str) {
- case 'solid':
- return 'none';
- case 'dot':
- return [1, 4 * w].join();
- case 'dash':
- return [4 * w, 4 * w].join();
- case 'dashdot':
- return [4 * w, 4 * w, 1, 4 * w].join();
- case 'longdash':
- return [8 * w, 4 * w].join();
- case 'longdashdot':
- return [8 * w, 4 * w, 1, 4 * w].join();
- default:
- return OpenLayers.String.trim(str).replace(/\s+/g, ",");
- }
- },
-
- /**
- * Method: createNode
- *
- * Parameters:
- * type - {String} Kind of node to draw
- * id - {String} Id for node
- *
- * Returns:
- * {DOMElement} A new node of the given type and id
- */
- createNode: function(type, id) {
- var node = document.createElementNS(this.xmlns, type);
- if (id) {
- node.setAttributeNS(null, "id", id);
- }
- return node;
- },
-
- /**
- * Method: nodeTypeCompare
- *
- * Parameters:
- * node - {SVGDomElement} An SVG element
- * type - {String} Kind of node
- *
- * Returns:
- * {Boolean} Whether or not the specified node is of the specified type
- */
- nodeTypeCompare: function(node, type) {
- return (type == node.nodeName);
- },
-
- /**
- * Method: createRenderRoot
- *
- * Returns:
- * {DOMElement} The specific render engine's root element
- */
- createRenderRoot: function() {
- var svg = this.nodeFactory(this.container.id + "_svgRoot", "svg");
- svg.style.display = "block";
- return svg;
- },
-
- /**
- * Method: createRoot
- *
- * Parameters:
- * suffix - {String} suffix to append to the id
- *
- * Returns:
- * {DOMElement}
- */
- createRoot: function(suffix) {
- return this.nodeFactory(this.container.id + suffix, "g");
- },
-
- /**
- * Method: createDefs
- *
- * Returns:
- * {DOMElement} The element to which we'll add the symbol definitions
- */
- createDefs: function() {
- var defs = this.nodeFactory(this.container.id + "_defs", "defs");
- this.rendererRoot.appendChild(defs);
- return defs;
- },
-
- /**************************************
- * *
- * GEOMETRY DRAWING FUNCTIONS *
- * *
- **************************************/
-
- /**
- * Method: drawPoint
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the point
- */
- drawPoint: function(node, geometry) {
- return this.drawCircle(node, geometry, 1);
- },
-
- /**
- * Method: drawCircle
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- * radius - {Float}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the circle
- */
- drawCircle: function(node, geometry, radius) {
- var resolution = this.getResolution();
- var x = ((geometry.x - this.featureDx) / resolution + this.left);
- var y = (this.top - geometry.y / resolution);
-
- if (this.inValidRange(x, y)) {
- node.setAttributeNS(null, "cx", x);
- node.setAttributeNS(null, "cy", y);
- node.setAttributeNS(null, "r", radius);
- return node;
- } else {
- return false;
- }
-
- },
-
- /**
- * Method: drawLineString
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components of
- * the linestring, or false if nothing could be drawn
- */
- drawLineString: function(node, geometry) {
- var componentsResult = this.getComponentsString(geometry.components);
- if (componentsResult.path) {
- node.setAttributeNS(null, "points", componentsResult.path);
- return (componentsResult.complete ? node : null);
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawLinearRing
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the linear ring, or false if nothing could be drawn
- */
- drawLinearRing: function(node, geometry) {
- var componentsResult = this.getComponentsString(geometry.components);
- if (componentsResult.path) {
- node.setAttributeNS(null, "points", componentsResult.path);
- return (componentsResult.complete ? node : null);
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawPolygon
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or null if the renderer could not draw all components
- * of the polygon, or false if nothing could be drawn
- */
- drawPolygon: function(node, geometry) {
- var d = "";
- var draw = true;
- var complete = true;
- var linearRingResult, path;
- for (var j=0, len=geometry.components.length; j<len; j++) {
- d += " M";
- linearRingResult = this.getComponentsString(
- geometry.components[j].components, " ");
- path = linearRingResult.path;
- if (path) {
- d += " " + path;
- complete = linearRingResult.complete && complete;
- } else {
- draw = false;
- }
- }
- d += " z";
- if (draw) {
- node.setAttributeNS(null, "d", d);
- node.setAttributeNS(null, "fill-rule", "evenodd");
- return complete ? node : null;
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawRectangle
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * node - {DOMElement}
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {DOMElement} or false if the renderer could not draw the rectangle
- */
- drawRectangle: function(node, geometry) {
- var resolution = this.getResolution();
- var x = ((geometry.x - this.featureDx) / resolution + this.left);
- var y = (this.top - geometry.y / resolution);
-
- if (this.inValidRange(x, y)) {
- node.setAttributeNS(null, "x", x);
- node.setAttributeNS(null, "y", y);
- node.setAttributeNS(null, "width", geometry.width / resolution);
- node.setAttributeNS(null, "height", geometry.height / resolution);
- return node;
- } else {
- return false;
- }
- },
-
- /**
- * Method: drawText
- * This method is only called by the renderer itself.
- *
- * Parameters:
- * featureId - {String}
- * style -
- * location - {<OpenLayers.Geometry.Point>}
- */
- drawText: function(featureId, style, location) {
- var drawOutline = (!!style.labelOutlineWidth);
- // First draw text in halo color and size and overlay the
- // normal text afterwards
- if (drawOutline) {
- var outlineStyle = OpenLayers.Util.extend({}, style);
- outlineStyle.fontColor = outlineStyle.labelOutlineColor;
- outlineStyle.fontStrokeColor = outlineStyle.labelOutlineColor;
- outlineStyle.fontStrokeWidth = style.labelOutlineWidth;
- if (style.labelOutlineOpacity) {
- outlineStyle.fontOpacity = style.labelOutlineOpacity;
- }
- delete outlineStyle.labelOutlineWidth;
- this.drawText(featureId, outlineStyle, location);
- }
-
- var resolution = this.getResolution();
-
- var x = ((location.x - this.featureDx) / resolution + this.left);
- var y = (location.y / resolution - this.top);
-
- var suffix = (drawOutline)?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX;
- var label = this.nodeFactory(featureId + suffix, "text");
-
- label.setAttributeNS(null, "x", x);
- label.setAttributeNS(null, "y", -y);
-
- if (style.fontColor) {
- label.setAttributeNS(null, "fill", style.fontColor);
- }
- if (style.fontStrokeColor) {
- label.setAttributeNS(null, "stroke", style.fontStrokeColor);
- }
- if (style.fontStrokeWidth) {
- label.setAttributeNS(null, "stroke-width", style.fontStrokeWidth);
- }
- if (style.fontOpacity) {
- label.setAttributeNS(null, "opacity", style.fontOpacity);
- }
- if (style.fontFamily) {
- label.setAttributeNS(null, "font-family", style.fontFamily);
- }
- if (style.fontSize) {
- label.setAttributeNS(null, "font-size", style.fontSize);
- }
- if (style.fontWeight) {
- label.setAttributeNS(null, "font-weight", style.fontWeight);
- }
- if (style.fontStyle) {
- label.setAttributeNS(null, "font-style", style.fontStyle);
- }
- if (style.labelSelect === true) {
- label.setAttributeNS(null, "pointer-events", "visible");
- label._featureId = featureId;
- } else {
- label.setAttributeNS(null, "pointer-events", "none");
- }
- var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign;
- label.setAttributeNS(null, "text-anchor",
- OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
-
- if (OpenLayers.IS_GECKO === true) {
- label.setAttributeNS(null, "dominant-baseline",
- OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
- }
-
- var labelRows = style.label.split('\n');
- var numRows = labelRows.length;
- while (label.childNodes.length > numRows) {
- label.removeChild(label.lastChild);
- }
- for (var i = 0; i < numRows; i++) {
- var tspan = this.nodeFactory(featureId + suffix + "_tspan_" + i, "tspan");
- if (style.labelSelect === true) {
- tspan._featureId = featureId;
- tspan._geometry = location;
- tspan._geometryClass = location.CLASS_NAME;
- }
- if (OpenLayers.IS_GECKO === false) {
- tspan.setAttributeNS(null, "baseline-shift",
- OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
- }
- tspan.setAttribute("x", x);
- if (i == 0) {
- var vfactor = OpenLayers.Renderer.SVG.LABEL_VFACTOR[align[1]];
- if (vfactor == null) {
- vfactor = -.5;
- }
- tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
- } else {
- tspan.setAttribute("dy", "1em");
- }
- tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
- if (!tspan.parentNode) {
- label.appendChild(tspan);
- }
- }
-
- if (!label.parentNode) {
- this.textRoot.appendChild(label);
- }
- },
-
- /**
- * Method: getComponentString
- *
- * Parameters:
- * components - {Array(<OpenLayers.Geometry.Point>)} Array of points
- * separator - {String} character between coordinate pairs. Defaults to ","
- *
- * Returns:
- * {Object} hash with properties "path" (the string created from the
- * components and "complete" (false if the renderer was unable to
- * draw all components)
- */
- getComponentsString: function(components, separator) {
- var renderCmp = [];
- var complete = true;
- var len = components.length;
- var strings = [];
- var str, component;
- for(var i=0; i<len; i++) {
- component = components[i];
- renderCmp.push(component);
- str = this.getShortString(component);
- if (str) {
- strings.push(str);
- } else {
- // The current component is outside the valid range. Let's
- // see if the previous or next component is inside the range.
- // If so, add the coordinate of the intersection with the
- // valid range bounds.
- if (i > 0) {
- if (this.getShortString(components[i - 1])) {
- strings.push(this.clipLine(components[i],
- components[i-1]));
- }
- }
- if (i < len - 1) {
- if (this.getShortString(components[i + 1])) {
- strings.push(this.clipLine(components[i],
- components[i+1]));
- }
- }
- complete = false;
- }
- }
-
- return {
- path: strings.join(separator || ","),
- complete: complete
- };
- },
-
- /**
- * Method: clipLine
- * Given two points (one inside the valid range, and one outside),
- * clips the line betweeen the two points so that the new points are both
- * inside the valid range.
- *
- * Parameters:
- * badComponent - {<OpenLayers.Geometry.Point>} original geometry of the
- * invalid point
- * goodComponent - {<OpenLayers.Geometry.Point>} original geometry of the
- * valid point
- * Returns
- * {String} the SVG coordinate pair of the clipped point (like
- * getShortString), or an empty string if both passed componets are at
- * the same point.
- */
- clipLine: function(badComponent, goodComponent) {
- if (goodComponent.equals(badComponent)) {
- return "";
- }
- var resolution = this.getResolution();
- var maxX = this.MAX_PIXEL - this.translationParameters.x;
- var maxY = this.MAX_PIXEL - this.translationParameters.y;
- var x1 = (goodComponent.x - this.featureDx) / resolution + this.left;
- var y1 = this.top - goodComponent.y / resolution;
- var x2 = (badComponent.x - this.featureDx) / resolution + this.left;
- var y2 = this.top - badComponent.y / resolution;
- var k;
- if (x2 < -maxX || x2 > maxX) {
- k = (y2 - y1) / (x2 - x1);
- x2 = x2 < 0 ? -maxX : maxX;
- y2 = y1 + (x2 - x1) * k;
- }
- if (y2 < -maxY || y2 > maxY) {
- k = (x2 - x1) / (y2 - y1);
- y2 = y2 < 0 ? -maxY : maxY;
- x2 = x1 + (y2 - y1) * k;
- }
- return x2 + "," + y2;
- },
-
- /**
- * Method: getShortString
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {String} or false if point is outside the valid range
- */
- getShortString: function(point) {
- var resolution = this.getResolution();
- var x = ((point.x - this.featureDx) / resolution + this.left);
- var y = (this.top - point.y / resolution);
-
- if (this.inValidRange(x, y)) {
- return x + "," + y;
- } else {
- return false;
- }
- },
-
- /**
- * Method: getPosition
- * Finds the position of an svg node.
- *
- * Parameters:
- * node - {DOMElement}
- *
- * Returns:
- * {Object} hash with x and y properties, representing the coordinates
- * within the svg coordinate system
- */
- getPosition: function(node) {
- return({
- x: parseFloat(node.getAttributeNS(null, "cx")),
- y: parseFloat(node.getAttributeNS(null, "cy"))
- });
- },
-
- /**
- * Method: importSymbol
- * add a new symbol definition from the rendererer's symbol hash
- *
- * Parameters:
- * graphicName - {String} name of the symbol to import
- *
- * Returns:
- * {DOMElement} - the imported symbol
- */
- importSymbol: function (graphicName) {
- if (!this.defs) {
- // create svg defs tag
- this.defs = this.createDefs();
- }
- var id = this.container.id + "-" + graphicName;
-
- // check if symbol already exists in the defs
- var existing = document.getElementById(id);
- if (existing != null) {
- return existing;
- }
-
- var symbol = OpenLayers.Renderer.symbol[graphicName];
- if (!symbol) {
- throw new Error(graphicName + ' is not a valid symbol name');
- }
-
- var symbolNode = this.nodeFactory(id, "symbol");
- var node = this.nodeFactory(null, "polygon");
- symbolNode.appendChild(node);
- var symbolExtent = new OpenLayers.Bounds(
- Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
-
- var points = [];
- var x,y;
- for (var i=0; i<symbol.length; i=i+2) {
- x = symbol[i];
- y = symbol[i+1];
- symbolExtent.left = Math.min(symbolExtent.left, x);
- symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
- symbolExtent.right = Math.max(symbolExtent.right, x);
- symbolExtent.top = Math.max(symbolExtent.top, y);
- points.push(x, ",", y);
- }
-
- node.setAttributeNS(null, "points", points.join(" "));
-
- var width = symbolExtent.getWidth();
- var height = symbolExtent.getHeight();
- // create a viewBox three times as large as the symbol itself,
- // to allow for strokeWidth being displayed correctly at the corners.
- var viewBox = [symbolExtent.left - width,
- symbolExtent.bottom - height, width * 3, height * 3];
- symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
- this.symbolMetrics[id] = [
- Math.max(width, height),
- symbolExtent.getCenterLonLat().lon,
- symbolExtent.getCenterLonLat().lat
- ];
-
- this.defs.appendChild(symbolNode);
- return symbolNode;
- },
-
- /**
- * Method: getFeatureIdFromEvent
- *
- * Parameters:
- * evt - {Object} An <OpenLayers.Event> object
- *
- * Returns:
- * {String} A feature id or undefined.
- */
- getFeatureIdFromEvent: function(evt) {
- var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
- if(!featureId) {
- var target = evt.target;
- featureId = target.parentNode && target != this.rendererRoot ?
- target.parentNode._featureId : undefined;
- }
- return featureId;
- },
-
- CLASS_NAME: "OpenLayers.Renderer.SVG"
-});
-
-/**
- * Constant: OpenLayers.Renderer.SVG.LABEL_ALIGN
- * {Object}
- */
-OpenLayers.Renderer.SVG.LABEL_ALIGN = {
- "l": "start",
- "r": "end",
- "b": "bottom",
- "t": "hanging"
-};
-
-/**
- * Constant: OpenLayers.Renderer.SVG.LABEL_VSHIFT
- * {Object}
- */
-OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
- // according to
- // http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
- // a baseline-shift of -70% shifts the text exactly from the
- // bottom to the top of the baseline, so -35% moves the text to
- // the center of the baseline.
- "t": "-70%",
- "b": "0"
-};
-
-/**
- * Constant: OpenLayers.Renderer.SVG.LABEL_VFACTOR
- * {Object}
- */
-OpenLayers.Renderer.SVG.LABEL_VFACTOR = {
- "t": 0,
- "b": -1
-};
-
-/**
- * Function: OpenLayers.Renderer.SVG.preventDefault
- * *Deprecated*. Use <OpenLayers.Event.preventDefault> method instead.
- * Used to prevent default events (especially opening images in a new tab on
- * ctrl-click) from being executed for externalGraphic symbols
- */
-OpenLayers.Renderer.SVG.preventDefault = function(e) {
- OpenLayers.Event.preventDefault(e);
-};
-/* ======================================================================
- OpenLayers/Format/JSON.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * Note:
- * This work draws heavily from the public domain JSON serializer/deserializer
- * at http://www.json.org/json.js. Rewritten so that it doesn't modify
- * basic data prototypes.
- */
-
-/**
- * @requires OpenLayers/Format.js
- */
-
-/**
- * Class: OpenLayers.Format.JSON
- * A parser to read/write JSON safely. Create a new instance with the
- * <OpenLayers.Format.JSON> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format>
- */
-OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, {
-
- /**
- * APIProperty: indent
- * {String} For "pretty" printing, the indent string will be used once for
- * each indentation level.
- */
- indent: " ",
-
- /**
- * APIProperty: space
- * {String} For "pretty" printing, the space string will be used after
- * the ":" separating a name/value pair.
- */
- space: " ",
-
- /**
- * APIProperty: newline
- * {String} For "pretty" printing, the newline string will be used at the
- * end of each name/value pair or array item.
- */
- newline: "\n",
-
- /**
- * Property: level
- * {Integer} For "pretty" printing, this is incremented/decremented during
- * serialization.
- */
- level: 0,
-
- /**
- * Property: pretty
- * {Boolean} Serialize with extra whitespace for structure. This is set
- * by the <write> method.
- */
- pretty: false,
-
- /**
- * Property: nativeJSON
- * {Boolean} Does the browser support native json?
- */
- nativeJSON: (function() {
- return !!(window.JSON && typeof JSON.parse == "function" && typeof JSON.stringify == "function");
- })(),
-
- /**
- * Constructor: OpenLayers.Format.JSON
- * Create a new parser for JSON.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
-
- /**
- * APIMethod: read
- * Deserialize a json string.
- *
- * Parameters:
- * json - {String} A JSON string
- * filter - {Function} A function which will be called for every key and
- * value at every level of the final result. Each value will be
- * replaced by the result of the filter function. This can be used to
- * reform generic objects into instances of classes, or to transform
- * date strings into Date objects.
- *
- * Returns:
- * {Object} An object, array, string, or number .
- */
- read: function(json, filter) {
- var object;
- if (this.nativeJSON) {
- object = JSON.parse(json, filter);
- } else try {
- /**
- * Parsing happens in three stages. In the first stage, we run the
- * text against a regular expression which looks for non-JSON
- * characters. We are especially concerned with '()' and 'new'
- * because they can cause invocation, and '=' because it can
- * cause mutation. But just to be safe, we will reject all
- * unexpected characters.
- */
- if (/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g, '@').
- replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
- replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
- /**
- * In the second stage we use the eval function to compile the
- * text into a JavaScript structure. The '{' operator is
- * subject to a syntactic ambiguity in JavaScript - it can
- * begin a block or an object literal. We wrap the text in
- * parens to eliminate the ambiguity.
- */
- object = eval('(' + json + ')');
-
- /**
- * In the optional third stage, we recursively walk the new
- * structure, passing each name/value pair to a filter
- * function for possible transformation.
- */
- if(typeof filter === 'function') {
- function walk(k, v) {
- if(v && typeof v === 'object') {
- for(var i in v) {
- if(v.hasOwnProperty(i)) {
- v[i] = walk(i, v[i]);
- }
- }
- }
- return filter(k, v);
- }
- object = walk('', object);
- }
- }
- } catch(e) {
- // Fall through if the regexp test fails.
- }
-
- if(this.keepData) {
- this.data = object;
- }
-
- return object;
- },
-
- /**
- * APIMethod: write
- * Serialize an object into a JSON string.
- *
- * Parameters:
- * value - {String} The object, array, string, number, boolean or date
- * to be serialized.
- * pretty - {Boolean} Structure the output with newlines and indentation.
- * Default is false.
- *
- * Returns:
- * {String} The JSON string representation of the input value.
- */
- write: function(value, pretty) {
- this.pretty = !!pretty;
- var json = null;
- var type = typeof value;
- if(this.serialize[type]) {
- try {
- json = (!this.pretty && this.nativeJSON) ?
- JSON.stringify(value) :
- this.serialize[type].apply(this, [value]);
- } catch(err) {
- OpenLayers.Console.error("Trouble serializing: " + err);
- }
- }
- return json;
- },
-
- /**
- * Method: writeIndent
- * Output an indentation string depending on the indentation level.
- *
- * Returns:
- * {String} An appropriate indentation string.
- */
- writeIndent: function() {
- var pieces = [];
- if(this.pretty) {
- for(var i=0; i<this.level; ++i) {
- pieces.push(this.indent);
- }
- }
- return pieces.join('');
- },
-
- /**
- * Method: writeNewline
- * Output a string representing a newline if in pretty printing mode.
- *
- * Returns:
- * {String} A string representing a new line.
- */
- writeNewline: function() {
- return (this.pretty) ? this.newline : '';
- },
-
- /**
- * Method: writeSpace
- * Output a string representing a space if in pretty printing mode.
- *
- * Returns:
- * {String} A space.
- */
- writeSpace: function() {
- return (this.pretty) ? this.space : '';
- },
-
- /**
- * Property: serialize
- * Object with properties corresponding to the serializable data types.
- * Property values are functions that do the actual serializing.
- */
- serialize: {
- /**
- * Method: serialize.object
- * Transform an object into a JSON string.
- *
- * Parameters:
- * object - {Object} The object to be serialized.
- *
- * Returns:
- * {String} A JSON string representing the object.
- */
- 'object': function(object) {
- // three special objects that we want to treat differently
- if(object == null) {
- return "null";
- }
- if(object.constructor == Date) {
- return this.serialize.date.apply(this, [object]);
- }
- if(object.constructor == Array) {
- return this.serialize.array.apply(this, [object]);
- }
- var pieces = ['{'];
- this.level += 1;
- var key, keyJSON, valueJSON;
-
- var addComma = false;
- for(key in object) {
- if(object.hasOwnProperty(key)) {
- // recursive calls need to allow for sub-classing
- keyJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
- [key, this.pretty]);
- valueJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
- [object[key], this.pretty]);
- if(keyJSON != null && valueJSON != null) {
- if(addComma) {
- pieces.push(',');
- }
- pieces.push(this.writeNewline(), this.writeIndent(),
- keyJSON, ':', this.writeSpace(), valueJSON);
- addComma = true;
- }
- }
- }
-
- this.level -= 1;
- pieces.push(this.writeNewline(), this.writeIndent(), '}');
- return pieces.join('');
- },
-
- /**
- * Method: serialize.array
- * Transform an array into a JSON string.
- *
- * Parameters:
- * array - {Array} The array to be serialized
- *
- * Returns:
- * {String} A JSON string representing the array.
- */
- 'array': function(array) {
- var json;
- var pieces = ['['];
- this.level += 1;
-
- for(var i=0, len=array.length; i<len; ++i) {
- // recursive calls need to allow for sub-classing
- json = OpenLayers.Format.JSON.prototype.write.apply(this,
- [array[i], this.pretty]);
- if(json != null) {
- if(i > 0) {
- pieces.push(',');
- }
- pieces.push(this.writeNewline(), this.writeIndent(), json);
- }
- }
-
- this.level -= 1;
- pieces.push(this.writeNewline(), this.writeIndent(), ']');
- return pieces.join('');
- },
-
- /**
- * Method: serialize.string
- * Transform a string into a JSON string.
- *
- * Parameters:
- * string - {String} The string to be serialized
- *
- * Returns:
- * {String} A JSON string representing the string.
- */
- 'string': function(string) {
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can simply slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe
- // sequences.
- var m = {
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- };
- if(/["\\\x00-\x1f]/.test(string)) {
- return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) {
- var c = m[b];
- if(c) {
- return c;
- }
- c = b.charCodeAt();
- return '\\u00' +
- Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }) + '"';
- }
- return '"' + string + '"';
- },
-
- /**
- * Method: serialize.number
- * Transform a number into a JSON string.
- *
- * Parameters:
- * number - {Number} The number to be serialized.
- *
- * Returns:
- * {String} A JSON string representing the number.
- */
- 'number': function(number) {
- return isFinite(number) ? String(number) : "null";
- },
-
- /**
- * Method: serialize.boolean
- * Transform a boolean into a JSON string.
- *
- * Parameters:
- * bool - {Boolean} The boolean to be serialized.
- *
- * Returns:
- * {String} A JSON string representing the boolean.
- */
- 'boolean': function(bool) {
- return String(bool);
- },
-
- /**
- * Method: serialize.object
- * Transform a date into a JSON string.
- *
- * Parameters:
- * date - {Date} The date to be serialized.
- *
- * Returns:
- * {String} A JSON string representing the date.
- */
- 'date': function(date) {
- function format(number) {
- // Format integers to have at least two digits.
- return (number < 10) ? '0' + number : number;
- }
- return '"' + date.getFullYear() + '-' +
- format(date.getMonth() + 1) + '-' +
- format(date.getDate()) + 'T' +
- format(date.getHours()) + ':' +
- format(date.getMinutes()) + ':' +
- format(date.getSeconds()) + '"';
- }
- },
-
- CLASS_NAME: "OpenLayers.Format.JSON"
-
-});
-/* ======================================================================
- OpenLayers/Format/GeoJSON.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Format/JSON.js
- * @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Geometry/MultiPoint.js
- * @requires OpenLayers/Geometry/LineString.js
- * @requires OpenLayers/Geometry/MultiLineString.js
- * @requires OpenLayers/Geometry/Polygon.js
- * @requires OpenLayers/Geometry/MultiPolygon.js
- * @requires OpenLayers/Console.js
- */
-
-/**
- * Class: OpenLayers.Format.GeoJSON
- * Read and write GeoJSON. Create a new parser with the
- * <OpenLayers.Format.GeoJSON> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Format.JSON>
- */
-OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, {
-
- /**
- * APIProperty: ignoreExtraDims
- * {Boolean} Ignore dimensions higher than 2 when reading geometry
- * coordinates.
- */
- ignoreExtraDims: false,
-
- /**
- * Constructor: OpenLayers.Format.GeoJSON
- * Create a new parser for GeoJSON.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * this instance.
- */
-
- /**
- * APIMethod: read
- * Deserialize a GeoJSON string.
- *
- * Parameters:
- * json - {String} A GeoJSON string
- * type - {String} Optional string that determines the structure of
- * the output. Supported values are "Geometry", "Feature", and
- * "FeatureCollection". If absent or null, a default of
- * "FeatureCollection" is assumed.
- * filter - {Function} A function which will be called for every key and
- * value at every level of the final result. Each value will be
- * replaced by the result of the filter function. This can be used to
- * reform generic objects into instances of classes, or to transform
- * date strings into Date objects.
- *
- * Returns:
- * {Object} The return depends on the value of the type argument. If type
- * is "FeatureCollection" (the default), the return will be an array
- * of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
- * must represent a single geometry, and the return will be an
- * <OpenLayers.Geometry>. If type is "Feature", the input json must
- * represent a single feature, and the return will be an
- * <OpenLayers.Feature.Vector>.
- */
- read: function(json, type, filter) {
- type = (type) ? type : "FeatureCollection";
- var results = null;
- var obj = null;
- if (typeof json == "string") {
- obj = OpenLayers.Format.JSON.prototype.read.apply(this,
- [json, filter]);
- } else {
- obj = json;
- }
- if(!obj) {
- OpenLayers.Console.error("Bad JSON: " + json);
- } else if(typeof(obj.type) != "string") {
- OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
- } else if(this.isValidType(obj, type)) {
- switch(type) {
- case "Geometry":
- try {
- results = this.parseGeometry(obj);
- } catch(err) {
- OpenLayers.Console.error(err);
- }
- break;
- case "Feature":
- try {
- results = this.parseFeature(obj);
- results.type = "Feature";
- } catch(err) {
- OpenLayers.Console.error(err);
- }
- break;
- case "FeatureCollection":
- // for type FeatureCollection, we allow input to be any type
- results = [];
- switch(obj.type) {
- case "Feature":
- try {
- results.push(this.parseFeature(obj));
- } catch(err) {
- results = null;
- OpenLayers.Console.error(err);
- }
- break;
- case "FeatureCollection":
- for(var i=0, len=obj.features.length; i<len; ++i) {
- try {
- results.push(this.parseFeature(obj.features[i]));
- } catch(err) {
- results = null;
- OpenLayers.Console.error(err);
- }
- }
- break;
- default:
- try {
- var geom = this.parseGeometry(obj);
- results.push(new OpenLayers.Feature.Vector(geom));
- } catch(err) {
- results = null;
- OpenLayers.Console.error(err);
- }
- }
- break;
- }
- }
- return results;
- },
-
- /**
- * Method: isValidType
- * Check if a GeoJSON object is a valid representative of the given type.
- *
- * Returns:
- * {Boolean} The object is valid GeoJSON object of the given type.
- */
- isValidType: function(obj, type) {
- var valid = false;
- switch(type) {
- case "Geometry":
- if(OpenLayers.Util.indexOf(
- ["Point", "MultiPoint", "LineString", "MultiLineString",
- "Polygon", "MultiPolygon", "Box", "GeometryCollection"],
- obj.type) == -1) {
- // unsupported geometry type
- OpenLayers.Console.error("Unsupported geometry type: " +
- obj.type);
- } else {
- valid = true;
- }
- break;
- case "FeatureCollection":
- // allow for any type to be converted to a feature collection
- valid = true;
- break;
- default:
- // for Feature types must match
- if(obj.type == type) {
- valid = true;
- } else {
- OpenLayers.Console.error("Cannot convert types from " +
- obj.type + " to " + type);
- }
- }
- return valid;
- },
-
- /**
- * Method: parseFeature
- * Convert a feature object from GeoJSON into an
- * <OpenLayers.Feature.Vector>.
- *
- * Parameters:
- * obj - {Object} An object created from a GeoJSON object
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>} A feature.
- */
- parseFeature: function(obj) {
- var feature, geometry, attributes, bbox;
- attributes = (obj.properties) ? obj.properties : {};
- bbox = (obj.geometry && obj.geometry.bbox) || obj.bbox;
- try {
- geometry = this.parseGeometry(obj.geometry);
- } catch(err) {
- // deal with bad geometries
- throw err;
- }
- feature = new OpenLayers.Feature.Vector(geometry, attributes);
- if(bbox) {
- feature.bounds = OpenLayers.Bounds.fromArray(bbox);
- }
- if(obj.id) {
- feature.fid = obj.id;
- }
- return feature;
- },
-
- /**
- * Method: parseGeometry
- * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>.
- *
- * Parameters:
- * obj - {Object} An object created from a GeoJSON object
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- parseGeometry: function(obj) {
- if (obj == null) {
- return null;
- }
- var geometry, collection = false;
- if(obj.type == "GeometryCollection") {
- if(!(OpenLayers.Util.isArray(obj.geometries))) {
- throw "GeometryCollection must have geometries array: " + obj;
- }
- var numGeom = obj.geometries.length;
- var components = new Array(numGeom);
- for(var i=0; i<numGeom; ++i) {
- components[i] = this.parseGeometry.apply(
- this, [obj.geometries[i]]
- );
- }
- geometry = new OpenLayers.Geometry.Collection(components);
- collection = true;
- } else {
- if(!(OpenLayers.Util.isArray(obj.coordinates))) {
- throw "Geometry must have coordinates array: " + obj;
- }
- if(!this.parseCoords[obj.type.toLowerCase()]) {
- throw "Unsupported geometry type: " + obj.type;
- }
- try {
- geometry = this.parseCoords[obj.type.toLowerCase()].apply(
- this, [obj.coordinates]
- );
- } catch(err) {
- // deal with bad coordinates
- throw err;
- }
- }
- // We don't reproject collections because the children are reprojected
- // for us when they are created.
- if (this.internalProjection && this.externalProjection && !collection) {
- geometry.transform(this.externalProjection,
- this.internalProjection);
- }
- return geometry;
- },
-
- /**
- * Property: parseCoords
- * Object with properties corresponding to the GeoJSON geometry types.
- * Property values are functions that do the actual parsing.
- */
- parseCoords: {
- /**
- * Method: parseCoords.point
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "point": function(array) {
- if (this.ignoreExtraDims == false &&
- array.length != 2) {
- throw "Only 2D points are supported: " + array;
- }
- return new OpenLayers.Geometry.Point(array[0], array[1]);
- },
-
- /**
- * Method: parseCoords.multipoint
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "multipoint": function(array) {
- var points = [];
- var p = null;
- for(var i=0, len=array.length; i<len; ++i) {
- try {
- p = this.parseCoords["point"].apply(this, [array[i]]);
- } catch(err) {
- throw err;
- }
- points.push(p);
- }
- return new OpenLayers.Geometry.MultiPoint(points);
- },
-
- /**
- * Method: parseCoords.linestring
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "linestring": function(array) {
- var points = [];
- var p = null;
- for(var i=0, len=array.length; i<len; ++i) {
- try {
- p = this.parseCoords["point"].apply(this, [array[i]]);
- } catch(err) {
- throw err;
- }
- points.push(p);
- }
- return new OpenLayers.Geometry.LineString(points);
- },
-
- /**
- * Method: parseCoords.multilinestring
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "multilinestring": function(array) {
- var lines = [];
- var l = null;
- for(var i=0, len=array.length; i<len; ++i) {
- try {
- l = this.parseCoords["linestring"].apply(this, [array[i]]);
- } catch(err) {
- throw err;
- }
- lines.push(l);
- }
- return new OpenLayers.Geometry.MultiLineString(lines);
- },
-
- /**
- * Method: parseCoords.polygon
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "polygon": function(array) {
- var rings = [];
- var r, l;
- for(var i=0, len=array.length; i<len; ++i) {
- try {
- l = this.parseCoords["linestring"].apply(this, [array[i]]);
- } catch(err) {
- throw err;
- }
- r = new OpenLayers.Geometry.LinearRing(l.components);
- rings.push(r);
- }
- return new OpenLayers.Geometry.Polygon(rings);
- },
-
- /**
- * Method: parseCoords.multipolygon
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "multipolygon": function(array) {
- var polys = [];
- var p = null;
- for(var i=0, len=array.length; i<len; ++i) {
- try {
- p = this.parseCoords["polygon"].apply(this, [array[i]]);
- } catch(err) {
- throw err;
- }
- polys.push(p);
- }
- return new OpenLayers.Geometry.MultiPolygon(polys);
- },
-
- /**
- * Method: parseCoords.box
- * Convert a coordinate array from GeoJSON into an
- * <OpenLayers.Geometry>.
- *
- * Parameters:
- * array - {Object} The coordinates array from the GeoJSON fragment.
- *
- * Returns:
- * {<OpenLayers.Geometry>} A geometry.
- */
- "box": function(array) {
- if(array.length != 2) {
- throw "GeoJSON box coordinates must have 2 elements";
- }
- return new OpenLayers.Geometry.Polygon([
- new OpenLayers.Geometry.LinearRing([
- new OpenLayers.Geometry.Point(array[0][0], array[0][1]),
- new OpenLayers.Geometry.Point(array[1][0], array[0][1]),
- new OpenLayers.Geometry.Point(array[1][0], array[1][1]),
- new OpenLayers.Geometry.Point(array[0][0], array[1][1]),
- new OpenLayers.Geometry.Point(array[0][0], array[0][1])
- ])
- ]);
- }
-
- },
-
- /**
- * APIMethod: write
- * Serialize a feature, geometry, array of features into a GeoJSON string.
- *
- * Parameters:
- * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>,
- * or an array of features.
- * pretty - {Boolean} Structure the output with newlines and indentation.
- * Default is false.
- *
- * Returns:
- * {String} The GeoJSON string representation of the input geometry,
- * features, or array of features.
- */
- write: function(obj, pretty) {
- var geojson = {
- "type": null
- };
- if(OpenLayers.Util.isArray(obj)) {
- geojson.type = "FeatureCollection";
- var numFeatures = obj.length;
- geojson.features = new Array(numFeatures);
- for(var i=0; i<numFeatures; ++i) {
- var element = obj[i];
- if(!element instanceof OpenLayers.Feature.Vector) {
- var msg = "FeatureCollection only supports collections " +
- "of features: " + element;
- throw msg;
- }
- geojson.features[i] = this.extract.feature.apply(
- this, [element]
- );
- }
- } else if (obj.CLASS_NAME.indexOf("OpenLayers.Geometry") == 0) {
- geojson = this.extract.geometry.apply(this, [obj]);
- } else if (obj instanceof OpenLayers.Feature.Vector) {
- geojson = this.extract.feature.apply(this, [obj]);
- if(obj.layer && obj.layer.projection) {
- geojson.crs = this.createCRSObject(obj);
- }
- }
- return OpenLayers.Format.JSON.prototype.write.apply(this,
- [geojson, pretty]);
- },
-
- /**
- * Method: createCRSObject
- * Create the CRS object for an object.
- *
- * Parameters:
- * object - {<OpenLayers.Feature.Vector>}
- *
- * Returns:
- * {Object} An object which can be assigned to the crs property
- * of a GeoJSON object.
- */
- createCRSObject: function(object) {
- var proj = object.layer.projection.toString();
- var crs = {};
- if (proj.match(/epsg:/i)) {
- var code = parseInt(proj.substring(proj.indexOf(":") + 1));
- if (code == 4326) {
- crs = {
- "type": "name",
- "properties": {
- "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
- }
- };
- } else {
- crs = {
- "type": "name",
- "properties": {
- "name": "EPSG:" + code
- }
- };
- }
- }
- return crs;
- },
-
- /**
- * Property: extract
- * Object with properties corresponding to the GeoJSON types.
- * Property values are functions that do the actual value extraction.
- */
- extract: {
- /**
- * Method: extract.feature
- * Return a partial GeoJSON object representing a single feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- *
- * Returns:
- * {Object} An object representing the point.
- */
- 'feature': function(feature) {
- var geom = this.extract.geometry.apply(this, [feature.geometry]);
- var json = {
- "type": "Feature",
- "properties": feature.attributes,
- "geometry": geom
- };
- if (feature.fid != null) {
- json.id = feature.fid;
- }
- return json;
- },
-
- /**
- * Method: extract.geometry
- * Return a GeoJSON object representing a single geometry.
- *
- * Parameters:
- * geometry - {<OpenLayers.Geometry>}
- *
- * Returns:
- * {Object} An object representing the geometry.
- */
- 'geometry': function(geometry) {
- if (geometry == null) {
- return null;
- }
- if (this.internalProjection && this.externalProjection) {
- geometry = geometry.clone();
- geometry.transform(this.internalProjection,
- this.externalProjection);
- }
- var geometryType = geometry.CLASS_NAME.split('.')[2];
- var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
- var json;
- if(geometryType == "Collection") {
- json = {
- "type": "GeometryCollection",
- "geometries": data
- };
- } else {
- json = {
- "type": geometryType,
- "coordinates": data
- };
- }
-
- return json;
- },
-
- /**
- * Method: extract.point
- * Return an array of coordinates from a point.
- *
- * Parameters:
- * point - {<OpenLayers.Geometry.Point>}
- *
- * Returns:
- * {Array} An array of coordinates representing the point.
- */
- 'point': function(point) {
- return [point.x, point.y];
- },
-
- /**
- * Method: extract.multipoint
- * Return an array of point coordinates from a multipoint.
- *
- * Parameters:
- * multipoint - {<OpenLayers.Geometry.MultiPoint>}
- *
- * Returns:
- * {Array} An array of point coordinate arrays representing
- * the multipoint.
- */
- 'multipoint': function(multipoint) {
- var array = [];
- for(var i=0, len=multipoint.components.length; i<len; ++i) {
- array.push(this.extract.point.apply(this, [multipoint.components[i]]));
- }
- return array;
- },
-
- /**
- * Method: extract.linestring
- * Return an array of coordinate arrays from a linestring.
- *
- * Parameters:
- * linestring - {<OpenLayers.Geometry.LineString>}
- *
- * Returns:
- * {Array} An array of coordinate arrays representing
- * the linestring.
- */
- 'linestring': function(linestring) {
- var array = [];
- for(var i=0, len=linestring.components.length; i<len; ++i) {
- array.push(this.extract.point.apply(this, [linestring.components[i]]));
- }
- return array;
- },
-
- /**
- * Method: extract.multilinestring
- * Return an array of linestring arrays from a linestring.
- *
- * Parameters:
- * multilinestring - {<OpenLayers.Geometry.MultiLineString>}
- *
- * Returns:
- * {Array} An array of linestring arrays representing
- * the multilinestring.
- */
- 'multilinestring': function(multilinestring) {
- var array = [];
- for(var i=0, len=multilinestring.components.length; i<len; ++i) {
- array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
- }
- return array;
- },
-
- /**
- * Method: extract.polygon
- * Return an array of linear ring arrays from a polygon.
- *
- * Parameters:
- * polygon - {<OpenLayers.Geometry.Polygon>}
- *
- * Returns:
- * {Array} An array of linear ring arrays representing the polygon.
- */
- 'polygon': function(polygon) {
- var array = [];
- for(var i=0, len=polygon.components.length; i<len; ++i) {
- array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
- }
- return array;
- },
-
- /**
- * Method: extract.multipolygon
- * Return an array of polygon arrays from a multipolygon.
- *
- * Parameters:
- * multipolygon - {<OpenLayers.Geometry.MultiPolygon>}
- *
- * Returns:
- * {Array} An array of polygon arrays representing
- * the multipolygon
- */
- 'multipolygon': function(multipolygon) {
- var array = [];
- for(var i=0, len=multipolygon.components.length; i<len; ++i) {
- array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
- }
- return array;
- },
-
- /**
- * Method: extract.collection
- * Return an array of geometries from a geometry collection.
- *
- * Parameters:
- * collection - {<OpenLayers.Geometry.Collection>}
- *
- * Returns:
- * {Array} An array of geometry objects representing the geometry
- * collection.
- */
- 'collection': function(collection) {
- var len = collection.components.length;
- var array = new Array(len);
- for(var i=0; i<len; ++i) {
- array[i] = this.extract.geometry.apply(
- this, [collection.components[i]]
- );
- }
- return array;
- }
-
-
- },
-
- CLASS_NAME: "OpenLayers.Format.GeoJSON"
-
-});
-/* ======================================================================
- OpenLayers/Control/DrawFeature.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Feature/Vector.js
- */
-
-/**
- * Class: OpenLayers.Control.DrawFeature
- * The DrawFeature control draws point, line or polygon features on a vector
- * layer when active.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.DrawFeature = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: layer
- * {<OpenLayers.Layer.Vector>}
- */
- layer: null,
-
- /**
- * Property: callbacks
- * {Object} The functions that are sent to the handler for callback
- */
- callbacks: 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)
- *
- * Supported event types (in addition to those from <OpenLayers.Control.events>):
- * featureadded - Triggered when a feature is added
- */
-
- /**
- * APIProperty: multi
- * {Boolean} Cast features to multi-part geometries before passing to the
- * layer. Default is false.
- */
- multi: false,
-
- /**
- * APIProperty: featureAdded
- * {Function} Called after each feature is added
- */
- featureAdded: function() {},
-
- /**
- * APIProperty: handlerOptions
- * {Object} Used to set non-default properties on the control's handler
- */
-
- /**
- * Constructor: OpenLayers.Control.DrawFeature
- *
- * Parameters:
- * layer - {<OpenLayers.Layer.Vector>}
- * handler - {<OpenLayers.Handler>}
- * options - {Object}
- */
- initialize: function(layer, handler, options) {
- OpenLayers.Control.prototype.initialize.apply(this, [options]);
- this.callbacks = OpenLayers.Util.extend(
- {
- done: this.drawFeature,
- modify: function(vertex, feature) {
- this.layer.events.triggerEvent(
- "sketchmodified", {vertex: vertex, feature: feature}
- );
- },
- create: function(vertex, feature) {
- this.layer.events.triggerEvent(
- "sketchstarted", {vertex: vertex, feature: feature}
- );
- }
- },
- this.callbacks
- );
- this.layer = layer;
- this.handlerOptions = this.handlerOptions || {};
- this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(
- this.handlerOptions.layerOptions, {
- renderers: layer.renderers, rendererOptions: layer.rendererOptions
- }
- );
- if (!("multi" in this.handlerOptions)) {
- this.handlerOptions.multi = this.multi;
- }
- var sketchStyle = this.layer.styleMap && this.layer.styleMap.styles.temporary;
- if(sketchStyle) {
- this.handlerOptions.layerOptions = OpenLayers.Util.applyDefaults(
- this.handlerOptions.layerOptions,
- {styleMap: new OpenLayers.StyleMap({"default": sketchStyle})}
- );
- }
- this.handler = new handler(this, this.callbacks, this.handlerOptions);
- },
-
- /**
- * Method: drawFeature
- */
- drawFeature: function(geometry) {
- var feature = new OpenLayers.Feature.Vector(geometry);
- var proceed = this.layer.events.triggerEvent(
- "sketchcomplete", {feature: feature}
- );
- if(proceed !== false) {
- feature.state = OpenLayers.State.INSERT;
- this.layer.addFeatures([feature]);
- this.featureAdded(feature);
- this.events.triggerEvent("featureadded",{feature : feature});
- }
- },
-
- /**
- * APIMethod: insertXY
- * Insert a point in the current sketch given x & y coordinates.
- *
- * Parameters:
- * x - {Number} The x-coordinate of the point.
- * y - {Number} The y-coordinate of the point.
- */
- insertXY: function(x, y) {
- if (this.handler && this.handler.line) {
- this.handler.insertXY(x, y);
- }
- },
-
- /**
- * APIMethod: insertDeltaXY
- * Insert a point given offsets from the previously inserted point.
- *
- * Parameters:
- * dx - {Number} The x-coordinate offset of the point.
- * dy - {Number} The y-coordinate offset of the point.
- */
- insertDeltaXY: function(dx, dy) {
- if (this.handler && this.handler.line) {
- this.handler.insertDeltaXY(dx, dy);
- }
- },
-
- /**
- * APIMethod: insertDirectionLength
- * Insert a point in the current sketch given a direction and a length.
- *
- * Parameters:
- * direction - {Number} Degrees clockwise from the positive x-axis.
- * length - {Number} Distance from the previously drawn point.
- */
- insertDirectionLength: function(direction, length) {
- if (this.handler && this.handler.line) {
- this.handler.insertDirectionLength(direction, length);
- }
- },
-
- /**
- * APIMethod: insertDeflectionLength
- * Insert a point in the current sketch given a deflection and a length.
- * The deflection should be degrees clockwise from the previously
- * digitized segment.
- *
- * Parameters:
- * deflection - {Number} Degrees clockwise from the previous segment.
- * length - {Number} Distance from the previously drawn point.
- */
- insertDeflectionLength: function(deflection, length) {
- if (this.handler && this.handler.line) {
- this.handler.insertDeflectionLength(deflection, length);
- }
- },
-
- /**
- * APIMethod: undo
- * Remove the most recently added point in the current sketch geometry.
- *
- * Returns:
- * {Boolean} An edit was undone.
- */
- undo: function() {
- return this.handler.undo && this.handler.undo();
- },
-
- /**
- * APIMethod: redo
- * Reinsert the most recently removed point resulting from an <undo> call.
- * The undo stack is deleted whenever a point is added by other means.
- *
- * Returns:
- * {Boolean} An edit was redone.
- */
- redo: function() {
- return this.handler.redo && this.handler.redo();
- },
-
- /**
- * APIMethod: finishSketch
- * Finishes the sketch without including the currently drawn point.
- * This method can be called to terminate drawing programmatically
- * instead of waiting for the user to end the sketch.
- */
- finishSketch: function() {
- this.handler.finishGeometry();
- },
-
- /**
- * APIMethod: cancel
- * Cancel the current sketch. This removes the current sketch and keeps
- * the drawing control active.
- */
- cancel: function() {
- this.handler.cancel();
- },
-
- CLASS_NAME: "OpenLayers.Control.DrawFeature"
-});
-/* ======================================================================
- OpenLayers/Handler/Pinch.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Pinch
- * The pinch handler is used to deal with sequences of browser events related
- * to pinch gestures. The handler is used by controls that want to know
- * when a pinch sequence begins, when a pinch is happening, and when it has
- * finished.
- *
- * Controls that use the pinch handler typically construct it with callbacks
- * for 'start', 'move', and 'done'. Callbacks for these keys are
- * called when the pinch begins, with each change, and when the pinch is
- * done.
- *
- * Create a new pinch handler with the <OpenLayers.Handler.Pinch> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Pinch = OpenLayers.Class(OpenLayers.Handler, {
-
- /**
- * Property: started
- * {Boolean} When a touchstart event is received, we want to record it,
- * but not set 'pinching' until the touchmove get started after
- * starting.
- */
- started: false,
-
- /**
- * Property: stopDown
- * {Boolean} Stop propagation of touchstart events from getting to
- * listeners on the same element. Default is false.
- */
- stopDown: false,
-
- /**
- * Property: pinching
- * {Boolean}
- */
- pinching: false,
-
- /**
- * Property: last
- * {Object} Object that store informations related to pinch last touch.
- */
- last: null,
-
- /**
- * Property: start
- * {Object} Object that store informations related to pinch touchstart.
- */
- start: null,
-
- /**
- * Constructor: OpenLayers.Handler.Pinch
- * Returns OpenLayers.Handler.Pinch
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handlers setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object containing functions to be called when
- * the pinch operation start, change, or is finished. The callbacks
- * should expect to receive an object argument, which contains
- * information about scale, distance, and position of touch points.
- * options - {Object}
- */
-
- /**
- * Method: touchstart
- * Handle touchstart events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchstart: function(evt) {
- var propagate = true;
- this.pinching = false;
- if (OpenLayers.Event.isMultiTouch(evt)) {
- this.started = true;
- this.last = this.start = {
- distance: this.getDistance(evt.touches),
- delta: 0,
- scale: 1
- };
- this.callback("start", [evt, this.start]);
- propagate = !this.stopDown;
- } else if (this.started) {
- // Some webkit versions send fake single-touch events during
- // multitouch, which cause the drag handler to trigger
- return false;
- } else {
- this.started = false;
- this.start = null;
- this.last = null;
- }
- // prevent document dragging
- OpenLayers.Event.preventDefault(evt);
- return propagate;
- },
-
- /**
- * Method: touchmove
- * Handle touchmove events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchmove: function(evt) {
- if (this.started && OpenLayers.Event.isMultiTouch(evt)) {
- this.pinching = true;
- var current = this.getPinchData(evt);
- this.callback("move", [evt, current]);
- this.last = current;
- // prevent document dragging
- OpenLayers.Event.stop(evt);
- } else if (this.started) {
- // Some webkit versions send fake single-touch events during
- // multitouch, which cause the drag handler to trigger
- return false;
- }
- return true;
- },
-
- /**
- * Method: touchend
- * Handle touchend events
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Boolean} Let the event propagate.
- */
- touchend: function(evt) {
- if (this.started && !OpenLayers.Event.isMultiTouch(evt)) {
- this.started = false;
- this.pinching = false;
- this.callback("done", [evt, this.start, this.last]);
- this.start = null;
- this.last = null;
- return false;
- }
- return true;
- },
-
- /**
- * Method: activate
- * Activate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully activated.
- */
- activate: function() {
- var activated = false;
- if (OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
- this.pinching = false;
- activated = true;
- }
- return activated;
- },
-
- /**
- * Method: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.started = false;
- this.pinching = false;
- this.start = null;
- this.last = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- /**
- * Method: getDistance
- * Get the distance in pixels between two touches.
- *
- * Parameters:
- * touches - {Array(Object)}
- *
- * Returns:
- * {Number} The distance in pixels.
- */
- getDistance: function(touches) {
- var t0 = touches[0];
- var t1 = touches[1];
- return Math.sqrt(
- Math.pow(t0.olClientX - t1.olClientX, 2) +
- Math.pow(t0.olClientY - t1.olClientY, 2)
- );
- },
-
-
- /**
- * Method: getPinchData
- * Get informations about the pinch event.
- *
- * Parameters:
- * evt - {Event}
- *
- * Returns:
- * {Object} Object that contains data about the current pinch.
- */
- getPinchData: function(evt) {
- var distance = this.getDistance(evt.touches);
- var scale = distance / this.start.distance;
- return {
- distance: distance,
- delta: this.last.distance - distance,
- scale: scale
- };
- },
-
- CLASS_NAME: "OpenLayers.Handler.Pinch"
-});
-
-/* ======================================================================
- OpenLayers/Handler/Polygon.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Handler/Path.js
- * @requires OpenLayers/Geometry/Polygon.js
- */
-
-/**
- * Class: OpenLayers.Handler.Polygon
- * Handler to draw a polygon on the map. Polygon is displayed on mouse down,
- * moves on mouse move, and is finished on mouse up.
- *
- * Inherits from:
- * - <OpenLayers.Handler.Path>
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Polygon = OpenLayers.Class(OpenLayers.Handler.Path, {
-
- /**
- * APIProperty: holeModifier
- * {String} Key modifier to trigger hole digitizing. Acceptable values are
- * "altKey", "shiftKey", or "ctrlKey". If not set, no hole digitizing
- * will take place. Default is null.
- */
- holeModifier: null,
-
- /**
- * Property: drawingHole
- * {Boolean} Currently drawing an interior ring.
- */
- drawingHole: false,
-
- /**
- * Property: polygon
- * {<OpenLayers.Feature.Vector>}
- */
- polygon: null,
-
- /**
- * Constructor: OpenLayers.Handler.Polygon
- * Create a Polygon Handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that owns this handler
- * callbacks - {Object} An object with a properties whose values are
- * functions. Various callbacks described below.
- * options - {Object} An optional object with properties to be set on the
- * handler
- *
- * Named callbacks:
- * create - Called when a sketch is first created. Callback called with
- * the creation point geometry and sketch feature.
- * modify - Called with each move of a vertex with the vertex (point)
- * geometry and the sketch feature.
- * point - Called as each point is added. Receives the new point geometry.
- * done - Called when the point drawing is finished. The callback will
- * recieve a single argument, the polygon geometry.
- * cancel - Called when the handler is deactivated while drawing. The
- * cancel callback will receive a geometry.
- */
-
- /**
- * Method: createFeature
- * Add temporary geometries
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The initial pixel location for the new
- * feature.
- */
- createFeature: function(pixel) {
- var lonlat = this.layer.getLonLatFromViewPortPx(pixel);
- var geometry = new OpenLayers.Geometry.Point(
- lonlat.lon, lonlat.lat
- );
- this.point = new OpenLayers.Feature.Vector(geometry);
- this.line = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.LinearRing([this.point.geometry])
- );
- this.polygon = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Polygon([this.line.geometry])
- );
- this.callback("create", [this.point.geometry, this.getSketch()]);
- this.point.geometry.clearBounds();
- this.layer.addFeatures([this.polygon, this.point], {silent: true});
- },
-
- /**
- * Method: addPoint
- * Add point to geometry.
- *
- * Parameters:
- * pixel - {<OpenLayers.Pixel>} The pixel location for the new point.
- */
- addPoint: function(pixel) {
- if(!this.drawingHole && this.holeModifier &&
- this.evt && this.evt[this.holeModifier]) {
- var geometry = this.point.geometry;
- var features = this.control.layer.features;
- var candidate, polygon;
- // look for intersections, last drawn gets priority
- for (var i=features.length-1; i>=0; --i) {
- candidate = features[i].geometry;
- if ((candidate instanceof OpenLayers.Geometry.Polygon ||
- candidate instanceof OpenLayers.Geometry.MultiPolygon) &&
- candidate.intersects(geometry)) {
- polygon = features[i];
- this.control.layer.removeFeatures([polygon], {silent: true});
- this.control.layer.events.registerPriority(
- "sketchcomplete", this, this.finalizeInteriorRing
- );
- this.control.layer.events.registerPriority(
- "sketchmodified", this, this.enforceTopology
- );
- polygon.geometry.addComponent(this.line.geometry);
- this.polygon = polygon;
- this.drawingHole = true;
- break;
- }
- }
- }
- OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments);
- },
-
- /**
- * Method: getCurrentPointIndex
- *
- * Returns:
- * {Number} The index of the most recently drawn point.
- */
- getCurrentPointIndex: function() {
- return this.line.geometry.components.length - 2;
- },
-
- /**
- * Method: enforceTopology
- * Simple topology enforcement for drawing interior rings. Ensures vertices
- * of interior rings are contained by exterior ring. Other topology
- * rules are enforced in <finalizeInteriorRing> to allow drawing of
- * rings that intersect only during the sketch (e.g. a "C" shaped ring
- * that nearly encloses another ring).
- */
- enforceTopology: function(event) {
- var point = event.vertex;
- var components = this.line.geometry.components;
- // ensure that vertices of interior ring are contained by exterior ring
- if (!this.polygon.geometry.intersects(point)) {
- var last = components[components.length-3];
- point.x = last.x;
- point.y = last.y;
- }
- },
-
- /**
- * Method: finishGeometry
- * Finish the geometry and send it back to the control.
- */
- finishGeometry: function() {
- var index = this.line.geometry.components.length - 2;
- this.line.geometry.removeComponent(this.line.geometry.components[index]);
- this.removePoint();
- this.finalize();
- },
-
- /**
- * Method: finalizeInteriorRing
- * Enforces that new ring has some area and doesn't contain vertices of any
- * other rings.
- */
- finalizeInteriorRing: function() {
- var ring = this.line.geometry;
- // ensure that ring has some area
- var modified = (ring.getArea() !== 0);
- if (modified) {
- // ensure that new ring doesn't intersect any other rings
- var rings = this.polygon.geometry.components;
- for (var i=rings.length-2; i>=0; --i) {
- if (ring.intersects(rings[i])) {
- modified = false;
- break;
- }
- }
- if (modified) {
- // ensure that new ring doesn't contain any other rings
- var target;
- outer: for (var i=rings.length-2; i>0; --i) {
- var points = rings[i].components;
- for (var j=0, jj=points.length; j<jj; ++j) {
- if (ring.containsPoint(points[j])) {
- modified = false;
- break outer;
- }
- }
- }
- }
- }
- if (modified) {
- if (this.polygon.state !== OpenLayers.State.INSERT) {
- this.polygon.state = OpenLayers.State.UPDATE;
- }
- } else {
- this.polygon.geometry.removeComponent(ring);
- }
- this.restoreFeature();
- return false;
- },
-
- /**
- * APIMethod: cancel
- * Finish the geometry and call the "cancel" callback.
- */
- cancel: function() {
- if (this.drawingHole) {
- this.polygon.geometry.removeComponent(this.line.geometry);
- this.restoreFeature(true);
- }
- return OpenLayers.Handler.Path.prototype.cancel.apply(this, arguments);
- },
-
- /**
- * Method: restoreFeature
- * Move the feature from the sketch layer to the target layer.
- *
- * Properties:
- * cancel - {Boolean} Cancel drawing. If falsey, the "sketchcomplete" event
- * will be fired.
- */
- restoreFeature: function(cancel) {
- this.control.layer.events.unregister(
- "sketchcomplete", this, this.finalizeInteriorRing
- );
- this.control.layer.events.unregister(
- "sketchmodified", this, this.enforceTopology
- );
- this.layer.removeFeatures([this.polygon], {silent: true});
- this.control.layer.addFeatures([this.polygon], {silent: true});
- this.drawingHole = false;
- if (!cancel) {
- // Re-trigger "sketchcomplete" so other listeners can do their
- // business. While this is somewhat sloppy (if a listener is
- // registered with registerPriority - not common - between the start
- // and end of a single ring drawing - very uncommon - it will be
- // called twice).
- // TODO: In 3.0, collapse sketch handlers into geometry specific
- // drawing controls.
- this.control.layer.events.triggerEvent(
- "sketchcomplete", {feature : this.polygon}
- );
- }
- },
-
- /**
- * Method: destroyFeature
- * Destroy temporary geometries
- *
- * Parameters:
- * force - {Boolean} Destroy even if persist is true.
- */
- destroyFeature: function(force) {
- OpenLayers.Handler.Path.prototype.destroyFeature.call(
- this, force);
- this.polygon = null;
- },
-
- /**
- * Method: drawFeature
- * Render geometries on the temporary layer.
- */
- drawFeature: function() {
- this.layer.drawFeature(this.polygon, this.style);
- this.layer.drawFeature(this.point, this.style);
- },
-
- /**
- * Method: getSketch
- * Return the sketch feature.
- *
- * Returns:
- * {<OpenLayers.Feature.Vector>}
- */
- getSketch: function() {
- return this.polygon;
- },
-
- /**
- * Method: getGeometry
- * Return the sketch geometry. If <multi> is true, this will return
- * a multi-part geometry.
- *
- * Returns:
- * {<OpenLayers.Geometry.Polygon>}
- */
- getGeometry: function() {
- var geometry = this.polygon && this.polygon.geometry;
- if(geometry && this.multi) {
- geometry = new OpenLayers.Geometry.MultiPolygon([geometry]);
- }
- return geometry;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Polygon"
-});
-/* ======================================================================
- OpenLayers/Control/Geolocate.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Geometry/Point.js
- * @requires OpenLayers/Projection.js
- */
-
-/**
- * Class: OpenLayers.Control.Geolocate
- * The Geolocate control wraps w3c geolocation API into control that can be
- * bound to a map, and generate events on location update
- *
- * To use this control requires to load the proj4js library if the projection
- * of the map is not EPSG:4326 or EPSG:900913.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.Geolocate = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * 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)
- *
- * Supported event types (in addition to those from <OpenLayers.Control.events>):
- * locationupdated - Triggered when browser return a new position. Listeners will
- * receive an object with a 'position' property which is the browser.geolocation.position
- * native object, as well as a 'point' property which is the location transformed in the
- * current map projection.
- * locationfailed - Triggered when geolocation has failed
- * locationuncapable - Triggered when control is activated on a browser
- * which doesn't support geolocation
- */
-
- /**
- * Property: geolocation
- * {Object} The geolocation engine, as a property to be possibly mocked.
- * This is set lazily to avoid a memory leak in IE9.
- */
- geolocation: null,
-
- /**
- * Property: available
- * {Boolean} The navigator.geolocation object is available.
- */
- available: ('geolocation' in navigator),
-
- /**
- * APIProperty: bind
- * {Boolean} If true, map center will be set on location update.
- */
- bind: true,
-
- /**
- * APIProperty: watch
- * {Boolean} If true, position will be update regularly.
- */
- watch: false,
-
- /**
- * APIProperty: geolocationOptions
- * {Object} Options to pass to the navigator's geolocation API. See
- * <http://dev.w3.org/geo/api/spec-source.html>. No specific
- * option is passed to the geolocation API by default.
- */
- geolocationOptions: null,
-
- /**
- * Constructor: OpenLayers.Control.Geolocate
- * Create a new control to deal with browser geolocation API
- *
- */
-
- /**
- * Method: destroy
- */
- destroy: function() {
- this.deactivate();
- OpenLayers.Control.prototype.destroy.apply(this, arguments);
- },
-
- /**
- * Method: activate
- * Activates the control.
- *
- * Returns:
- * {Boolean} The control was effectively activated.
- */
- activate: function () {
- if (this.available && !this.geolocation) {
- // set lazily to avoid IE9 memory leak
- this.geolocation = navigator.geolocation;
- }
- if (!this.geolocation) {
- this.events.triggerEvent("locationuncapable");
- return false;
- }
- if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
- if (this.watch) {
- this.watchId = this.geolocation.watchPosition(
- OpenLayers.Function.bind(this.geolocate, this),
- OpenLayers.Function.bind(this.failure, this),
- this.geolocationOptions
- );
- } else {
- this.getCurrentLocation();
- }
- return true;
- }
- return false;
- },
-
- /**
- * Method: deactivate
- * Deactivates the control.
- *
- * Returns:
- * {Boolean} The control was effectively deactivated.
- */
- deactivate: function () {
- if (this.active && this.watchId !== null) {
- this.geolocation.clearWatch(this.watchId);
- }
- return OpenLayers.Control.prototype.deactivate.apply(
- this, arguments
- );
- },
-
- /**
- * Method: geolocate
- * Activates the control.
- *
- */
- geolocate: function (position) {
- var center = new OpenLayers.LonLat(
- position.coords.longitude,
- position.coords.latitude
- ).transform(
- new OpenLayers.Projection("EPSG:4326"),
- this.map.getProjectionObject()
- );
- if (this.bind) {
- this.map.setCenter(center);
- }
- this.events.triggerEvent("locationupdated", {
- position: position,
- point: new OpenLayers.Geometry.Point(
- center.lon, center.lat
- )
- });
- },
-
- /**
- * APIMethod: getCurrentLocation
- *
- * Returns:
- * {Boolean} Returns true if a event will be fired (successfull
- * registration)
- */
- getCurrentLocation: function() {
- if (!this.active || this.watch) {
- return false;
- }
- this.geolocation.getCurrentPosition(
- OpenLayers.Function.bind(this.geolocate, this),
- OpenLayers.Function.bind(this.failure, this),
- this.geolocationOptions
- );
- return true;
- },
-
- /**
- * Method: failure
- * method called on browser's geolocation failure
- *
- */
- failure: function (error) {
- this.events.triggerEvent("locationfailed", {error: error});
- },
-
- CLASS_NAME: "OpenLayers.Control.Geolocate"
-});
-/* ======================================================================
- OpenLayers/Protocol/HTTP.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Protocol.js
- * @requires OpenLayers/Request/XMLHttpRequest.js
- */
-
-/**
- * if application uses the query string, for example, for BBOX parameters,
- * OpenLayers/Format/QueryStringFilter.js should be included in the build config file
- */
-
-/**
- * Class: OpenLayers.Protocol.HTTP
- * A basic HTTP protocol for vector layers. Create a new instance with the
- * <OpenLayers.Protocol.HTTP> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Protocol>
- */
-OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
-
- /**
- * Property: url
- * {String} Service URL, read-only, set through the options
- * passed to constructor.
- */
- url: null,
-
- /**
- * Property: headers
- * {Object} HTTP request headers, read-only, set through the options
- * passed to the constructor,
- * Example: {'Content-Type': 'plain/text'}
- */
- headers: null,
-
- /**
- * Property: params
- * {Object} Parameters of GET requests, read-only, set through the options
- * passed to the constructor,
- * Example: {'bbox': '5,5,5,5'}
- */
- params: null,
-
- /**
- * Property: callback
- * {Object} Function to be called when the <read>, <create>,
- * <update>, <delete> or <commit> operation completes, read-only,
- * set through the options passed to the constructor.
- */
- callback: null,
-
- /**
- * Property: scope
- * {Object} Callback execution scope, read-only, set through the
- * options passed to the constructor.
- */
- scope: null,
-
- /**
- * APIProperty: readWithPOST
- * {Boolean} true if read operations are done with POST requests
- * instead of GET, defaults to false.
- */
- readWithPOST: false,
-
- /**
- * APIProperty: updateWithPOST
- * {Boolean} true if update operations are done with POST requests
- * defaults to false.
- */
- updateWithPOST: false,
-
- /**
- * APIProperty: deleteWithPOST
- * {Boolean} true if delete operations are done with POST requests
- * defaults to false.
- * if true, POST data is set to output of format.write().
- */
- deleteWithPOST: false,
-
- /**
- * Property: wildcarded.
- * {Boolean} If true percent signs are added around values
- * read from LIKE filters, for example if the protocol
- * read method is passed a LIKE filter whose property
- * is "foo" and whose value is "bar" the string
- * "foo__ilike=%bar%" will be sent in the query string;
- * defaults to false.
- */
- wildcarded: false,
-
- /**
- * APIProperty: srsInBBOX
- * {Boolean} Include the SRS identifier in BBOX query string parameter.
- * Default is false. If true and the layer has a projection object set,
- * any BBOX filter will be serialized with a fifth item identifying the
- * projection. E.g. bbox=-1000,-1000,1000,1000,EPSG:900913
- */
- srsInBBOX: false,
-
- /**
- * Constructor: OpenLayers.Protocol.HTTP
- * A class for giving layers generic HTTP protocol.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Valid options include:
- * url - {String}
- * headers - {Object}
- * params - {Object} URL parameters for GET requests
- * format - {<OpenLayers.Format>}
- * callback - {Function}
- * scope - {Object}
- */
- initialize: function(options) {
- options = options || {};
- this.params = {};
- this.headers = {};
- OpenLayers.Protocol.prototype.initialize.apply(this, arguments);
-
- if (!this.filterToParams && OpenLayers.Format.QueryStringFilter) {
- var format = new OpenLayers.Format.QueryStringFilter({
- wildcarded: this.wildcarded,
- srsInBBOX: this.srsInBBOX
- });
- this.filterToParams = function(filter, params) {
- return format.write(filter, params);
- };
- }
- },
-
- /**
- * APIMethod: destroy
- * Clean up the protocol.
- */
- destroy: function() {
- this.params = null;
- this.headers = null;
- OpenLayers.Protocol.prototype.destroy.apply(this);
- },
-
- /**
- * APIMethod: filterToParams
- * Optional method to translate an <OpenLayers.Filter> object into an object
- * that can be serialized as request query string provided. If a custom
- * method is not provided, the filter will be serialized using the
- * <OpenLayers.Format.QueryStringFilter> class.
- *
- * Parameters:
- * filter - {<OpenLayers.Filter>} filter to convert.
- * params - {Object} The parameters object.
- *
- * Returns:
- * {Object} The resulting parameters object.
- */
-
- /**
- * APIMethod: read
- * Construct a request for reading new features.
- *
- * Parameters:
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Valid options:
- * url - {String} Url for the request.
- * params - {Object} Parameters to get serialized as a query string.
- * headers - {Object} Headers to be set on the request.
- * filter - {<OpenLayers.Filter>} Filter to get serialized as a
- * query string.
- * readWithPOST - {Boolean} If the request should be done with POST.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
- * references the HTTP request, this object is also passed to the
- * callback function when the request completes, its "features" property
- * is then populated with the features received from the server.
- */
- read: function(options) {
- OpenLayers.Protocol.prototype.read.apply(this, arguments);
- options = options || {};
- options.params = OpenLayers.Util.applyDefaults(
- options.params, this.options.params);
- options = OpenLayers.Util.applyDefaults(options, this.options);
- if (options.filter && this.filterToParams) {
- options.params = this.filterToParams(
- options.filter, options.params
- );
- }
- var readWithPOST = (options.readWithPOST !== undefined) ?
- options.readWithPOST : this.readWithPOST;
- var resp = new OpenLayers.Protocol.Response({requestType: "read"});
- if(readWithPOST) {
- var headers = options.headers || {};
- headers["Content-Type"] = "application/x-www-form-urlencoded";
- resp.priv = OpenLayers.Request.POST({
- url: options.url,
- callback: this.createCallback(this.handleRead, resp, options),
- data: OpenLayers.Util.getParameterString(options.params),
- headers: headers
- });
- } else {
- resp.priv = OpenLayers.Request.GET({
- url: options.url,
- callback: this.createCallback(this.handleRead, resp, options),
- params: options.params,
- headers: options.headers
- });
- }
- return resp;
- },
-
- /**
- * Method: handleRead
- * Individual callbacks are created for read, create and update, should
- * a subclass need to override each one separately.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * the user callback.
- * options - {Object} The user options passed to the read call.
- */
- handleRead: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * APIMethod: create
- * Construct a request for writing newly created features.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes, its "features" property is then populated with the
- * the features received from the server.
- */
- create: function(features, options) {
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: features,
- requestType: "create"
- });
-
- resp.priv = OpenLayers.Request.POST({
- url: options.url,
- callback: this.createCallback(this.handleCreate, resp, options),
- headers: options.headers,
- data: this.format.write(features)
- });
-
- return resp;
- },
-
- /**
- * Method: handleCreate
- * Called the the request issued by <create> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the create call.
- */
- handleCreate: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * APIMethod: update
- * Construct a request updating modified feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes, its "features" property is then populated with the
- * the feature received from the server.
- */
- update: function(feature, options) {
- options = options || {};
- var url = options.url ||
- feature.url ||
- this.options.url + "/" + feature.fid;
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: feature,
- requestType: "update"
- });
-
- var method = this.updateWithPOST ? "POST" : "PUT";
- resp.priv = OpenLayers.Request[method]({
- url: url,
- callback: this.createCallback(this.handleUpdate, resp, options),
- headers: options.headers,
- data: this.format.write(feature)
- });
-
- return resp;
- },
-
- /**
- * Method: handleUpdate
- * Called the the request issued by <update> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the update call.
- */
- handleUpdate: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * APIMethod: delete
- * Construct a request deleting a removed feature.
- *
- * Parameters:
- * feature - {<OpenLayers.Feature.Vector>}
- * options - {Object} Optional object for configuring the request.
- * This object is modified and should not be reused.
- *
- * Returns:
- * {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
- * object, whose "priv" property references the HTTP request, this
- * object is also passed to the callback function when the request
- * completes.
- */
- "delete": function(feature, options) {
- options = options || {};
- var url = options.url ||
- feature.url ||
- this.options.url + "/" + feature.fid;
- options = OpenLayers.Util.applyDefaults(options, this.options);
-
- var resp = new OpenLayers.Protocol.Response({
- reqFeatures: feature,
- requestType: "delete"
- });
-
- var method = this.deleteWithPOST ? "POST" : "DELETE";
- var requestOptions = {
- url: url,
- callback: this.createCallback(this.handleDelete, resp, options),
- headers: options.headers
- };
- if (this.deleteWithPOST) {
- requestOptions.data = this.format.write(feature);
- }
- resp.priv = OpenLayers.Request[method](requestOptions);
-
- return resp;
- },
-
- /**
- * Method: handleDelete
- * Called the the request issued by <delete> is complete. May be overridden
- * by subclasses.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the delete call.
- */
- handleDelete: function(resp, options) {
- this.handleResponse(resp, options);
- },
-
- /**
- * Method: handleResponse
- * Called by CRUD specific handlers.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>} The response object to pass to
- * any user callback.
- * options - {Object} The user options passed to the create, read, update,
- * or delete call.
- */
- handleResponse: function(resp, options) {
- var request = resp.priv;
- if(options.callback) {
- if(request.status >= 200 && request.status < 300) {
- // success
- if(resp.requestType != "delete") {
- resp.features = this.parseFeatures(request);
- }
- resp.code = OpenLayers.Protocol.Response.SUCCESS;
- } else {
- // failure
- resp.code = OpenLayers.Protocol.Response.FAILURE;
- }
- options.callback.call(options.scope, resp);
- }
- },
-
- /**
- * Method: parseFeatures
- * Read HTTP response body and return features.
- *
- * Parameters:
- * request - {XMLHttpRequest} The request object
- *
- * Returns:
- * {Array({<OpenLayers.Feature.Vector>})} or
- * {<OpenLayers.Feature.Vector>} Array of features or a single feature.
- */
- parseFeatures: function(request) {
- var doc = request.responseXML;
- if (!doc || !doc.documentElement) {
- doc = request.responseText;
- }
- if (!doc || doc.length <= 0) {
- return null;
- }
- return this.format.read(doc);
- },
-
- /**
- * APIMethod: commit
- * Iterate over each feature and take action based on the feature state.
- * Possible actions are create, update and delete.
- *
- * Parameters:
- * features - {Array({<OpenLayers.Feature.Vector>})}
- * options - {Object} Optional object for setting up intermediate commit
- * callbacks.
- *
- * Valid options:
- * create - {Object} Optional object to be passed to the <create> method.
- * update - {Object} Optional object to be passed to the <update> method.
- * delete - {Object} Optional object to be passed to the <delete> method.
- * callback - {Function} Optional function to be called when the commit
- * is complete.
- * scope - {Object} Optional object to be set as the scope of the callback.
- *
- * Returns:
- * {Array(<OpenLayers.Protocol.Response>)} An array of response objects,
- * one per request made to the server, each object's "priv" property
- * references the corresponding HTTP request.
- */
- commit: function(features, options) {
- options = OpenLayers.Util.applyDefaults(options, this.options);
- var resp = [], nResponses = 0;
-
- // Divide up features before issuing any requests. This properly
- // counts requests in the event that any responses come in before
- // all requests have been issued.
- var types = {};
- types[OpenLayers.State.INSERT] = [];
- types[OpenLayers.State.UPDATE] = [];
- types[OpenLayers.State.DELETE] = [];
- var feature, list, requestFeatures = [];
- for(var i=0, len=features.length; i<len; ++i) {
- feature = features[i];
- list = types[feature.state];
- if(list) {
- list.push(feature);
- requestFeatures.push(feature);
- }
- }
- // tally up number of requests
- var nRequests = (types[OpenLayers.State.INSERT].length > 0 ? 1 : 0) +
- types[OpenLayers.State.UPDATE].length +
- types[OpenLayers.State.DELETE].length;
-
- // This response will be sent to the final callback after all the others
- // have been fired.
- var success = true;
- var finalResponse = new OpenLayers.Protocol.Response({
- reqFeatures: requestFeatures
- });
-
- function insertCallback(response) {
- var len = response.features ? response.features.length : 0;
- var fids = new Array(len);
- for(var i=0; i<len; ++i) {
- fids[i] = response.features[i].fid;
- }
- finalResponse.insertIds = fids;
- callback.apply(this, [response]);
- }
-
- function callback(response) {
- this.callUserCallback(response, options);
- success = success && response.success();
- nResponses++;
- if (nResponses >= nRequests) {
- if (options.callback) {
- finalResponse.code = success ?
- OpenLayers.Protocol.Response.SUCCESS :
- OpenLayers.Protocol.Response.FAILURE;
- options.callback.apply(options.scope, [finalResponse]);
- }
- }
- }
-
- // start issuing requests
- var queue = types[OpenLayers.State.INSERT];
- if(queue.length > 0) {
- resp.push(this.create(
- queue, OpenLayers.Util.applyDefaults(
- {callback: insertCallback, scope: this}, options.create
- )
- ));
- }
- queue = types[OpenLayers.State.UPDATE];
- for(var i=queue.length-1; i>=0; --i) {
- resp.push(this.update(
- queue[i], OpenLayers.Util.applyDefaults(
- {callback: callback, scope: this}, options.update
- ))
- );
- }
- queue = types[OpenLayers.State.DELETE];
- for(var i=queue.length-1; i>=0; --i) {
- resp.push(this["delete"](
- queue[i], OpenLayers.Util.applyDefaults(
- {callback: callback, scope: this}, options["delete"]
- ))
- );
- }
- return resp;
- },
-
- /**
- * APIMethod: abort
- * Abort an ongoing request, the response object passed to
- * this method must come from this HTTP protocol (as a result
- * of a create, read, update, delete or commit operation).
- *
- * Parameters:
- * response - {<OpenLayers.Protocol.Response>}
- */
- abort: function(response) {
- if (response) {
- response.priv.abort();
- }
- },
-
- /**
- * Method: callUserCallback
- * This method is used from within the commit method each time an
- * an HTTP response is received from the server, it is responsible
- * for calling the user-supplied callbacks.
- *
- * Parameters:
- * resp - {<OpenLayers.Protocol.Response>}
- * options - {Object} The map of options passed to the commit call.
- */
- callUserCallback: function(resp, options) {
- var opt = options[resp.requestType];
- if(opt && opt.callback) {
- opt.callback.call(opt.scope, resp);
- }
- },
-
- CLASS_NAME: "OpenLayers.Protocol.HTTP"
-});
-/* ======================================================================
- OpenLayers/Control/DragPan.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control.js
- * @requires OpenLayers/Handler/Drag.js
- */
-
-/**
- * Class: OpenLayers.Control.DragPan
- * The DragPan control pans the map with a drag of the mouse.
- *
- * Inherits from:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.DragPan = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: type
- * {OpenLayers.Control.TYPES}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
- /**
- * Property: panned
- * {Boolean} The map moved.
- */
- panned: false,
-
- /**
- * Property: interval
- * {Integer} The number of milliseconds that should ellapse before
- * panning the map again. Defaults to 0 milliseconds, which means that
- * no separate cycle is used for panning. In most cases you won't want
- * to change this value. For slow machines/devices larger values can be
- * tried out.
- */
- interval: 0,
-
- /**
- * APIProperty: documentDrag
- * {Boolean} If set to true, mouse dragging will continue even if the
- * mouse cursor leaves the map viewport. Default is false.
- */
- documentDrag: false,
-
- /**
- * Property: kinetic
- * {<OpenLayers.Kinetic>} The OpenLayers.Kinetic object.
- */
- kinetic: null,
-
- /**
- * APIProperty: enableKinetic
- * {Boolean} Set this option to enable "kinetic dragging". Can be
- * set to true or to an object. If set to an object this
- * object will be passed to the {<OpenLayers.Kinetic>}
- * constructor. Defaults to true.
- * To get kinetic dragging, ensure that OpenLayers/Kinetic.js is
- * included in your build config.
- */
- enableKinetic: true,
-
- /**
- * APIProperty: kineticInterval
- * {Integer} Interval in milliseconds between 2 steps in the "kinetic
- * scrolling". Applies only if enableKinetic is set. Defaults
- * to 10 milliseconds.
- */
- kineticInterval: 10,
-
-
- /**
- * Method: draw
- * Creates a Drag handler, using <panMap> and
- * <panMapDone> as callbacks.
- */
- draw: function() {
- if (this.enableKinetic && OpenLayers.Kinetic) {
- var config = {interval: this.kineticInterval};
- if(typeof this.enableKinetic === "object") {
- config = OpenLayers.Util.extend(config, this.enableKinetic);
- }
- this.kinetic = new OpenLayers.Kinetic(config);
- }
- this.handler = new OpenLayers.Handler.Drag(this, {
- "move": this.panMap,
- "done": this.panMapDone,
- "down": this.panMapStart
- }, {
- interval: this.interval,
- documentDrag: this.documentDrag
- }
- );
- },
-
- /**
- * Method: panMapStart
- */
- panMapStart: function() {
- if(this.kinetic) {
- this.kinetic.begin();
- }
- },
-
- /**
- * Method: panMap
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMap: function(xy) {
- if(this.kinetic) {
- this.kinetic.update(xy);
- }
- this.panned = true;
- this.map.pan(
- this.handler.last.x - xy.x,
- this.handler.last.y - xy.y,
- {dragging: true, animate: false}
- );
- },
-
- /**
- * Method: panMapDone
- * Finish the panning operation. Only call setCenter (through <panMap>)
- * if the map has actually been moved.
- *
- * Parameters:
- * xy - {<OpenLayers.Pixel>} Pixel of the mouse position
- */
- panMapDone: function(xy) {
- if(this.panned) {
- var res = null;
- if (this.kinetic) {
- res = this.kinetic.end(xy);
- }
- this.map.pan(
- this.handler.last.x - xy.x,
- this.handler.last.y - xy.y,
- {dragging: !!res, animate: false}
- );
- if (res) {
- var self = this;
- this.kinetic.move(res, function(x, y, end) {
- self.map.pan(x, y, {dragging: !end, animate: false});
- });
- }
- this.panned = false;
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.DragPan"
-});
-/* ======================================================================
- OpenLayers/Control/PinchZoom.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler/Pinch.js
- */
-
-/**
- * Class: OpenLayers.Control.PinchZoom
- *
- * Inherits:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: type
- * {OpenLayers.Control.TYPES}
- */
- type: OpenLayers.Control.TYPE_TOOL,
-
- /**
- * Property: pinchOrigin
- * {Object} Cached object representing the pinch start (in pixels).
- */
- pinchOrigin: null,
-
- /**
- * Property: currentCenter
- * {Object} Cached object representing the latest pinch center (in pixels).
- */
- currentCenter: null,
-
- /**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * true.
- */
- autoActivate: true,
-
- /**
- * APIProperty: preserveCenter
- * {Boolean} Set this to true if you don't want the map center to change
- * while pinching. For example you may want to set preserveCenter to
- * true when the user location is being watched and you want to preserve
- * the user location at the center of the map even if he zooms in or
- * out using pinch. This property's value can be changed any time on an
- * existing instance. Default is false.
- */
- preserveCenter: false,
-
- /**
- * APIProperty: handlerOptions
- * {Object} Used to set non-default properties on the pinch handler
- */
-
- /**
- * Constructor: OpenLayers.Control.PinchZoom
- * Create a control for zooming with pinch gestures. This works on devices
- * with multi-touch support.
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * the control
- */
- initialize: function(options) {
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- this.handler = new OpenLayers.Handler.Pinch(this, {
- start: this.pinchStart,
- move: this.pinchMove,
- done: this.pinchDone
- }, this.handlerOptions);
- },
-
- /**
- * Method: pinchStart
- *
- * Parameters:
- * evt - {Event}
- * pinchData - {Object} pinch data object related to the current touchmove
- * of the pinch gesture. This give us the current scale of the pinch.
- */
- pinchStart: function(evt, pinchData) {
- var xy = (this.preserveCenter) ?
- this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy;
- this.pinchOrigin = xy;
- this.currentCenter = xy;
- },
-
- /**
- * Method: pinchMove
- *
- * Parameters:
- * evt - {Event}
- * pinchData - {Object} pinch data object related to the current touchmove
- * of the pinch gesture. This give us the current scale of the pinch.
- */
- pinchMove: function(evt, pinchData) {
- var scale = pinchData.scale;
- var containerOrigin = this.map.layerContainerOriginPx;
- var pinchOrigin = this.pinchOrigin;
- var current = (this.preserveCenter) ?
- this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy;
-
- var dx = Math.round((containerOrigin.x + current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x));
- var dy = Math.round((containerOrigin.y + current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y));
-
- this.map.applyTransform(dx, dy, scale);
- this.currentCenter = current;
- },
-
- /**
- * Method: pinchDone
- *
- * Parameters:
- * evt - {Event}
- * start - {Object} pinch data object related to the touchstart event that
- * started the pinch gesture.
- * last - {Object} pinch data object related to the last touchmove event
- * of the pinch gesture. This give us the final scale of the pinch.
- */
- pinchDone: function(evt, start, last) {
- this.map.applyTransform();
- var zoom = this.map.getZoomForResolution(this.map.getResolution() / last.scale, true);
- if (zoom !== this.map.getZoom() || !this.currentCenter.equals(this.pinchOrigin)) {
- var resolution = this.map.getResolutionForZoom(zoom);
-
- var location = this.map.getLonLatFromPixel(this.pinchOrigin);
- var zoomPixel = this.currentCenter;
- var size = this.map.getSize();
-
- location.lon += resolution * ((size.w / 2) - zoomPixel.x);
- location.lat -= resolution * ((size.h / 2) - zoomPixel.y);
-
- // Force a reflow before calling setCenter. This is to work
- // around an issue occuring in iOS.
- //
- // See https://github.com/openlayers/openlayers/pull/351.
- //
- // Without a reflow setting the layer container div's top left
- // style properties to "0px" - as done in Map.moveTo when zoom
- // is changed - won't actually correctly reposition the layer
- // container div.
- //
- // Also, we need to use a statement that the Google Closure
- // compiler won't optimize away.
- this.map.div.clientWidth = this.map.div.clientWidth;
-
- this.map.setCenter(location, zoom);
- }
- },
-
- CLASS_NAME: "OpenLayers.Control.PinchZoom"
-
-});
-/* ======================================================================
- OpenLayers/Handler/Click.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Handler.js
- */
-
-/**
- * Class: OpenLayers.Handler.Click
- * A handler for mouse clicks. The intention of this handler is to give
- * controls more flexibility with handling clicks. Browsers trigger
- * click events twice for a double-click. In addition, the mousedown,
- * mousemove, mouseup sequence fires a click event. With this handler,
- * controls can decide whether to ignore clicks associated with a double
- * click. By setting a <pixelTolerance>, controls can also ignore clicks
- * that include a drag. Create a new instance with the
- * <OpenLayers.Handler.Click> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Handler>
- */
-OpenLayers.Handler.Click = OpenLayers.Class(OpenLayers.Handler, {
- /**
- * APIProperty: delay
- * {Number} Number of milliseconds between clicks before the event is
- * considered a double-click.
- */
- delay: 300,
-
- /**
- * APIProperty: single
- * {Boolean} Handle single clicks. Default is true. If false, clicks
- * will not be reported. If true, single-clicks will be reported.
- */
- single: true,
-
- /**
- * APIProperty: double
- * {Boolean} Handle double-clicks. Default is false.
- */
- 'double': false,
-
- /**
- * APIProperty: pixelTolerance
- * {Number} Maximum number of pixels between mouseup and mousedown for an
- * event to be considered a click. Default is 0. If set to an
- * integer value, clicks with a drag greater than the value will be
- * ignored. This property can only be set when the handler is
- * constructed.
- */
- pixelTolerance: 0,
-
- /**
- * APIProperty: dblclickTolerance
- * {Number} Maximum distance in pixels between clicks for a sequence of
- * events to be considered a double click. Default is 13. If the
- * distance between two clicks is greater than this value, a double-
- * click will not be fired.
- */
- dblclickTolerance: 13,
-
- /**
- * APIProperty: stopSingle
- * {Boolean} Stop other listeners from being notified of clicks. Default
- * is false. If true, any listeners registered before this one for
- * click or rightclick events will not be notified.
- */
- stopSingle: false,
-
- /**
- * APIProperty: stopDouble
- * {Boolean} Stop other listeners from being notified of double-clicks.
- * Default is false. If true, any click listeners registered before
- * this one will not be notified of *any* double-click events.
- *
- * The one caveat with stopDouble is that given a map with two click
- * handlers, one with stopDouble true and the other with stopSingle
- * true, the stopSingle handler should be activated last to get
- * uniform cross-browser performance. Since IE triggers one click
- * with a dblclick and FF triggers two, if a stopSingle handler is
- * activated first, all it gets in IE is a single click when the
- * second handler stops propagation on the dblclick.
- */
- stopDouble: false,
-
- /**
- * Property: timerId
- * {Number} The id of the timeout waiting to clear the <delayedCall>.
- */
- timerId: null,
-
- /**
- * Property: down
- * {Object} Object that store relevant information about the last
- * mousedown or touchstart. Its 'xy' OpenLayers.Pixel property gives
- * the average location of the mouse/touch event. Its 'touches'
- * property records clientX/clientY of each touches.
- */
- down: null,
-
- /**
- * Property: last
- * {Object} Object that store relevant information about the last
- * mousemove or touchmove. Its 'xy' OpenLayers.Pixel property gives
- * the average location of the mouse/touch event. Its 'touches'
- * property records clientX/clientY of each touches.
- */
- last: null,
-
- /**
- * Property: first
- * {Object} When waiting for double clicks, this object will store
- * information about the first click in a two click sequence.
- */
- first: null,
-
- /**
- * Property: rightclickTimerId
- * {Number} The id of the right mouse timeout waiting to clear the
- * <delayedEvent>.
- */
- rightclickTimerId: null,
-
- /**
- * Constructor: OpenLayers.Handler.Click
- * Create a new click handler.
- *
- * Parameters:
- * control - {<OpenLayers.Control>} The control that is making use of
- * this handler. If a handler is being used without a control, the
- * handler's setMap method must be overridden to deal properly with
- * the map.
- * callbacks - {Object} An object with keys corresponding to callbacks
- * that will be called by the handler. The callbacks should
- * expect to recieve a single argument, the click event.
- * Callbacks for 'click' and 'dblclick' are supported.
- * options - {Object} Optional object whose properties will be set on the
- * handler.
- */
-
- /**
- * Method: touchstart
- * Handle touchstart.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- touchstart: function(evt) {
- this.startTouch();
- this.down = this.getEventInfo(evt);
- this.last = this.getEventInfo(evt);
- return true;
- },
-
- /**
- * Method: touchmove
- * Store position of last move, because touchend event can have
- * an empty "touches" property.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- touchmove: function(evt) {
- this.last = this.getEventInfo(evt);
- return true;
- },
-
- /**
- * Method: touchend
- * Correctly set event xy property, and add lastTouches to have
- * touches property from last touchstart or touchmove
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- touchend: function(evt) {
- // touchstart may not have been allowed to propagate
- if (this.down) {
- evt.xy = this.last.xy;
- evt.lastTouches = this.last.touches;
- this.handleSingle(evt);
- this.down = null;
- }
- return true;
- },
-
- /**
- * Method: mousedown
- * Handle mousedown.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mousedown: function(evt) {
- this.down = this.getEventInfo(evt);
- this.last = this.getEventInfo(evt);
- return true;
- },
-
- /**
- * Method: mouseup
- * Handle mouseup. Installed to support collection of right mouse events.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- mouseup: function (evt) {
- var propagate = true;
-
- // Collect right mouse clicks from the mouseup
- // IE - ignores the second right click in mousedown so using
- // mouseup instead
- if (this.checkModifiers(evt) && this.control.handleRightClicks &&
- OpenLayers.Event.isRightClick(evt)) {
- propagate = this.rightclick(evt);
- }
-
- return propagate;
- },
-
- /**
- * Method: rightclick
- * Handle rightclick. For a dblrightclick, we get two clicks so we need
- * to always register for dblrightclick to properly handle single
- * clicks.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- rightclick: function(evt) {
- if(this.passesTolerance(evt)) {
- if(this.rightclickTimerId != null) {
- //Second click received before timeout this must be
- // a double click
- this.clearTimer();
- this.callback('dblrightclick', [evt]);
- return !this.stopDouble;
- } else {
- //Set the rightclickTimerId, send evt only if double is
- // true else trigger single
- var clickEvent = this['double'] ?
- OpenLayers.Util.extend({}, evt) :
- this.callback('rightclick', [evt]);
-
- var delayedRightCall = OpenLayers.Function.bind(
- this.delayedRightCall,
- this,
- clickEvent
- );
- this.rightclickTimerId = window.setTimeout(
- delayedRightCall, this.delay
- );
- }
- }
- return !this.stopSingle;
- },
-
- /**
- * Method: delayedRightCall
- * Sets <rightclickTimerId> to null. And optionally triggers the
- * rightclick callback if evt is set.
- */
- delayedRightCall: function(evt) {
- this.rightclickTimerId = null;
- if (evt) {
- this.callback('rightclick', [evt]);
- }
- },
-
- /**
- * Method: click
- * Handle click events from the browser. This is registered as a listener
- * for click events and should not be called from other events in this
- * handler.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- click: function(evt) {
- if (!this.last) {
- this.last = this.getEventInfo(evt);
- }
- this.handleSingle(evt);
- return !this.stopSingle;
- },
-
- /**
- * Method: dblclick
- * Handle dblclick. For a dblclick, we get two clicks in some browsers
- * (FF) and one in others (IE). So we need to always register for
- * dblclick to properly handle single clicks. This method is registered
- * as a listener for the dblclick browser event. It should *not* be
- * called by other methods in this handler.
- *
- * Returns:
- * {Boolean} Continue propagating this event.
- */
- dblclick: function(evt) {
- this.handleDouble(evt);
- return !this.stopDouble;
- },
-
- /**
- * Method: handleDouble
- * Handle double-click sequence.
- */
- handleDouble: function(evt) {
- if (this.passesDblclickTolerance(evt)) {
- if (this["double"]) {
- this.callback("dblclick", [evt]);
- }
- // to prevent a dblclick from firing the click callback in IE
- this.clearTimer();
- }
- },
-
- /**
- * Method: handleSingle
- * Handle single click sequence.
- */
- handleSingle: function(evt) {
- if (this.passesTolerance(evt)) {
- if (this.timerId != null) {
- // already received a click
- if (this.last.touches && this.last.touches.length === 1) {
- // touch device, no dblclick event - this may be a double
- if (this["double"]) {
- // on Android don't let the browser zoom on the page
- OpenLayers.Event.preventDefault(evt);
- }
- this.handleDouble(evt);
- }
- // if we're not in a touch environment we clear the click timer
- // if we've got a second touch, we'll get two touchend events
- if (!this.last.touches || this.last.touches.length !== 2) {
- this.clearTimer();
- }
- } else {
- // remember the first click info so we can compare to the second
- this.first = this.getEventInfo(evt);
- // set the timer, send evt only if single is true
- //use a clone of the event object because it will no longer
- //be a valid event object in IE in the timer callback
- var clickEvent = this.single ?
- OpenLayers.Util.extend({}, evt) : null;
- this.queuePotentialClick(clickEvent);
- }
- }
- },
-
- /**
- * Method: queuePotentialClick
- * This method is separated out largely to make testing easier (so we
- * don't have to override window.setTimeout)
- */
- queuePotentialClick: function(evt) {
- this.timerId = window.setTimeout(
- OpenLayers.Function.bind(this.delayedCall, this, evt),
- this.delay
- );
- },
-
- /**
- * Method: passesTolerance
- * Determine whether the event is within the optional pixel tolerance. Note
- * that the pixel tolerance check only works if mousedown events get to
- * the listeners registered here. If they are stopped by other elements,
- * the <pixelTolerance> will have no effect here (this method will always
- * return true).
- *
- * Returns:
- * {Boolean} The click is within the pixel tolerance (if specified).
- */
- passesTolerance: function(evt) {
- var passes = true;
- if (this.pixelTolerance != null && this.down && this.down.xy) {
- passes = this.pixelTolerance >= this.down.xy.distanceTo(evt.xy);
- // for touch environments, we also enforce that all touches
- // start and end within the given tolerance to be considered a click
- if (passes && this.touch &&
- this.down.touches.length === this.last.touches.length) {
- // the touchend event doesn't come with touches, so we check
- // down and last
- for (var i=0, ii=this.down.touches.length; i<ii; ++i) {
- if (this.getTouchDistance(
- this.down.touches[i],
- this.last.touches[i]
- ) > this.pixelTolerance) {
- passes = false;
- break;
- }
- }
- }
- }
- return passes;
- },
-
- /**
- * Method: getTouchDistance
- *
- * Returns:
- * {Boolean} The pixel displacement between two touches.
- */
- getTouchDistance: function(from, to) {
- return Math.sqrt(
- Math.pow(from.clientX - to.clientX, 2) +
- Math.pow(from.clientY - to.clientY, 2)
- );
- },
-
- /**
- * Method: passesDblclickTolerance
- * Determine whether the event is within the optional double-cick pixel
- * tolerance.
- *
- * Returns:
- * {Boolean} The click is within the double-click pixel tolerance.
- */
- passesDblclickTolerance: function(evt) {
- var passes = true;
- if (this.down && this.first) {
- passes = this.down.xy.distanceTo(this.first.xy) <= this.dblclickTolerance;
- }
- return passes;
- },
-
- /**
- * Method: clearTimer
- * Clear the timer and set <timerId> to null.
- */
- clearTimer: function() {
- if (this.timerId != null) {
- window.clearTimeout(this.timerId);
- this.timerId = null;
- }
- if (this.rightclickTimerId != null) {
- window.clearTimeout(this.rightclickTimerId);
- this.rightclickTimerId = null;
- }
- },
-
- /**
- * Method: delayedCall
- * Sets <timerId> to null. And optionally triggers the click callback if
- * evt is set.
- */
- delayedCall: function(evt) {
- this.timerId = null;
- if (evt) {
- this.callback("click", [evt]);
- }
- },
-
- /**
- * Method: getEventInfo
- * This method allows us to store event information without storing the
- * actual event. In touch devices (at least), the same event is
- * modified between touchstart, touchmove, and touchend.
- *
- * Returns:
- * {Object} An object with event related info.
- */
- getEventInfo: function(evt) {
- var touches;
- if (evt.touches) {
- var len = evt.touches.length;
- touches = new Array(len);
- var touch;
- for (var i=0; i<len; i++) {
- touch = evt.touches[i];
- touches[i] = {
- clientX: touch.olClientX,
- clientY: touch.olClientY
- };
- }
- }
- return {
- xy: evt.xy,
- touches: touches
- };
- },
-
- /**
- * APIMethod: deactivate
- * Deactivate the handler.
- *
- * Returns:
- * {Boolean} The handler was successfully deactivated.
- */
- deactivate: function() {
- var deactivated = false;
- if(OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
- this.clearTimer();
- this.down = null;
- this.first = null;
- this.last = null;
- deactivated = true;
- }
- return deactivated;
- },
-
- CLASS_NAME: "OpenLayers.Handler.Click"
-});
-/* ======================================================================
- OpenLayers/Control/TouchNavigation.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Control/DragPan.js
- * @requires OpenLayers/Control/PinchZoom.js
- * @requires OpenLayers/Handler/Click.js
- */
-
-/**
- * Class: OpenLayers.Control.TouchNavigation
- * The navigation control handles map browsing with touch events (dragging,
- * double-tapping, tap with two fingers, and pinch zoom). Create a new
- * control with the <OpenLayers.Control.TouchNavigation> constructor.
- *
- * If you’re only targeting touch enabled devices with your mapping application,
- * you can create a map with only a TouchNavigation control. The
- * <OpenLayers.Control.Navigation> control is mobile ready by default, but
- * you can generate a smaller build of the library by only including this
- * touch navigation control if you aren't concerned about mouse interaction.
- *
- * Inherits:
- * - <OpenLayers.Control>
- */
-OpenLayers.Control.TouchNavigation = OpenLayers.Class(OpenLayers.Control, {
-
- /**
- * Property: dragPan
- * {<OpenLayers.Control.DragPan>}
- */
- dragPan: null,
-
- /**
- * APIProperty: dragPanOptions
- * {Object} Options passed to the DragPan control.
- */
- dragPanOptions: null,
-
- /**
- * Property: pinchZoom
- * {<OpenLayers.Control.PinchZoom>}
- */
- pinchZoom: null,
-
- /**
- * APIProperty: pinchZoomOptions
- * {Object} Options passed to the PinchZoom control.
- */
- pinchZoomOptions: null,
-
- /**
- * APIProperty: clickHandlerOptions
- * {Object} Options passed to the Click handler.
- */
- clickHandlerOptions: null,
-
- /**
- * APIProperty: documentDrag
- * {Boolean} Allow panning of the map by dragging outside map viewport.
- * Default is false.
- */
- documentDrag: false,
-
- /**
- * APIProperty: autoActivate
- * {Boolean} Activate the control when it is added to a map. Default is
- * true.
- */
- autoActivate: true,
-
- /**
- * Constructor: OpenLayers.Control.TouchNavigation
- * Create a new navigation control
- *
- * Parameters:
- * options - {Object} An optional object whose properties will be set on
- * the control
- */
- initialize: function(options) {
- this.handlers = {};
- OpenLayers.Control.prototype.initialize.apply(this, arguments);
- },
-
- /**
- * 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() {
- this.deactivate();
- if(this.dragPan) {
- this.dragPan.destroy();
- }
- this.dragPan = null;
- if (this.pinchZoom) {
- this.pinchZoom.destroy();
- delete this.pinchZoom;
- }
- OpenLayers.Control.prototype.destroy.apply(this,arguments);
- },
-
- /**
- * Method: activate
- */
- activate: function() {
- if(OpenLayers.Control.prototype.activate.apply(this,arguments)) {
- this.dragPan.activate();
- this.handlers.click.activate();
- this.pinchZoom.activate();
- return true;
- }
- return false;
- },
-
- /**
- * Method: deactivate
- */
- deactivate: function() {
- if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)) {
- this.dragPan.deactivate();
- this.handlers.click.deactivate();
- this.pinchZoom.deactivate();
- return true;
- }
- return false;
- },
-
- /**
- * Method: draw
- */
- draw: function() {
- var clickCallbacks = {
- click: this.defaultClick,
- dblclick: this.defaultDblClick
- };
- var clickOptions = OpenLayers.Util.extend({
- "double": true,
- stopDouble: true,
- pixelTolerance: 2
- }, this.clickHandlerOptions);
- this.handlers.click = new OpenLayers.Handler.Click(
- this, clickCallbacks, clickOptions
- );
- this.dragPan = new OpenLayers.Control.DragPan(
- OpenLayers.Util.extend({
- map: this.map,
- documentDrag: this.documentDrag
- }, this.dragPanOptions)
- );
- this.dragPan.draw();
- this.pinchZoom = new OpenLayers.Control.PinchZoom(
- OpenLayers.Util.extend({map: this.map}, this.pinchZoomOptions)
- );
- },
-
- /**
- * Method: defaultClick
- *
- * Parameters:
- * evt - {Event}
- */
- defaultClick: function (evt) {
- if(evt.lastTouches && evt.lastTouches.length == 2) {
- this.map.zoomOut();
- }
- },
-
- /**
- * Method: defaultDblClick
- *
- * Parameters:
- * evt - {Event}
- */
- defaultDblClick: function (evt) {
- this.map.zoomTo(this.map.zoom + 1, evt.xy);
- },
-
- CLASS_NAME: "OpenLayers.Control.TouchNavigation"
-});
-/* ======================================================================
- OpenLayers/Protocol/WFS/v1_0_0.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-/**
- * @requires OpenLayers/Protocol/WFS/v1.js
- * @requires OpenLayers/Format/WFST/v1_0_0.js
- */
-
-/**
- * Class: OpenLayers.Protocol.WFS.v1_0_0
- * A WFS v1.0.0 protocol for vector layers. Create a new instance with the
- * <OpenLayers.Protocol.WFS.v1_0_0> constructor.
- *
- * Inherits from:
- * - <OpenLayers.Protocol.WFS.v1>
- */
-OpenLayers.Protocol.WFS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WFS.v1, {
-
- /**
- * Property: version
- * {String} WFS version number.
- */
- version: "1.0.0",
-
- /**
- * Constructor: OpenLayers.Protocol.WFS.v1_0_0
- * A class for giving layers WFS v1.0.0 protocol.
- *
- * Parameters:
- * options - {Object} Optional object whose properties will be set on the
- * instance.
- *
- * Valid options properties:
- * featureType - {String} Local (without prefix) feature typeName (required).
- * featureNS - {String} Feature namespace (optional).
- * featurePrefix - {String} Feature namespace alias (optional - only used
- * if featureNS is provided). Default is 'feature'.
- * geometryName - {String} Name of geometry attribute. Default is 'the_geom'.
- */
-
- CLASS_NAME: "OpenLayers.Protocol.WFS.v1_0_0"
-});
-/* ======================================================================
- OpenLayers/TileManager.js
- ====================================================================== */
-
-/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
- * full list of contributors). Published under the 2-clause BSD license.
- * See license.txt in the OpenLayers distribution or repository for the
- * full text of the license. */
-
-
-/**
- * @requires OpenLayers/Util.js
- * @requires OpenLayers/BaseTypes.js
- * @requires OpenLayers/BaseTypes/Element.js
- * @requires OpenLayers/Layer/Grid.js
- * @requires OpenLayers/Tile/Image.js
- */
-
-/**
- * Class: OpenLayers.TileManager
- * Provides queueing of image requests and caching of image elements.
- *
- * Queueing avoids unnecessary image requests while changing zoom levels
- * quickly, and helps improve dragging performance on mobile devices that show
- * a lag in dragging when loading of new images starts. <zoomDelay> and
- * <moveDelay> are the configuration options to control this behavior.
- *
- * Caching avoids setting the src on image elements for images that have already
- * been used. Several maps can share a TileManager instance, in which case each
- * map gets its own tile queue, but all maps share the same tile cache.
- */
-OpenLayers.TileManager = OpenLayers.Class({
-
- /**
- * APIProperty: cacheSize
- * {Number} Number of image elements to keep referenced in this instance's
- * cache for fast reuse. Default is 256.
- */
- cacheSize: 256,
-
- /**
- * APIProperty: tilesPerFrame
- * {Number} Number of queued tiles to load per frame (see <frameDelay>).
- * Default is 2.
- */
- tilesPerFrame: 2,
-
- /**
- * APIProperty: frameDelay
- * {Number} Delay between tile loading frames (see <tilesPerFrame>) in
- * milliseconds. Default is 16.
- */
- frameDelay: 16,
-
- /**
- * APIProperty: moveDelay
- * {Number} Delay in milliseconds after a map's move event before loading
- * tiles. Default is 100.
- */
- moveDelay: 100,
-
- /**
- * APIProperty: zoomDelay
- * {Number} Delay in milliseconds after a map's zoomend event before loading
- * tiles. Default is 200.
- */
- zoomDelay: 200,
-
- /**
- * Property: maps
- * {Array(<OpenLayers.Map>)} The maps to manage tiles on.
- */
- maps: null,
-
- /**
- * Property: tileQueueId
- * {Object} The ids of the <drawTilesFromQueue> loop, keyed by map id.
- */
- tileQueueId: null,
-
- /**
- * Property: tileQueue
- * {Object(Array(<OpenLayers.Tile>))} Tiles queued for drawing, keyed by
- * map id.
- */
- tileQueue: null,
-
- /**
- * Property: tileCache
- * {Object} Cached image elements, keyed by URL.
- */
- tileCache: null,
-
- /**
- * Property: tileCacheIndex
- * {Array(String)} URLs of cached tiles. First entry is the least recently
- * used.
- */
- tileCacheIndex: null,
-
- /**
- * Constructor: OpenLayers.TileManager
- * Constructor for a new <OpenLayers.TileManager> instance.
- *
- * Parameters:
- * options - {Object} Configuration for this instance.
- */
- initialize: function(options) {
- OpenLayers.Util.extend(this, options);
- this.maps = [];
- this.tileQueueId = {};
- this.tileQueue = {};
- this.tileCache = {};
- this.tileCacheIndex = [];
- },
-
- /**
- * Method: addMap
- * Binds this instance to a map
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- addMap: function(map) {
- if (this._destroyed || !OpenLayers.Layer.Grid) {
- return;
- }
- this.maps.push(map);
- this.tileQueue[map.id] = [];
- for (var i=0, ii=map.layers.length; i<ii; ++i) {
- this.addLayer({layer: map.layers[i]});
- }
- map.events.on({
- move: this.move,
- zoomend: this.zoomEnd,
- changelayer: this.changeLayer,
- addlayer: this.addLayer,
- preremovelayer: this.removeLayer,
- scope: this
- });
- },
-
- /**
- * Method: removeMap
- * Unbinds this instance from a map
- *
- * Parameters:
- * map - {<OpenLayers.Map>}
- */
- removeMap: function(map) {
- if (this._destroyed || !OpenLayers.Layer.Grid) {
- return;
- }
- window.clearTimeout(this.tileQueueId[map.id]);
- if (map.layers) {
- for (var i=0, ii=map.layers.length; i<ii; ++i) {
- this.removeLayer({layer: map.layers[i]});
- }
- }
- if (map.events) {
- map.events.un({
- move: this.move,
- zoomend: this.zoomEnd,
- changelayer: this.changeLayer,
- addlayer: this.addLayer,
- preremovelayer: this.removeLayer,
- scope: this
- });
- }
- delete this.tileQueue[map.id];
- delete this.tileQueueId[map.id];
- OpenLayers.Util.removeItem(this.maps, map);
- },
-
- /**
- * Method: move
- * Handles the map's move event
- *
- * Parameters:
- * evt - {Object} Listener argument
- */
- move: function(evt) {
- this.updateTimeout(evt.object, this.moveDelay, true);
- },
-
- /**
- * Method: zoomEnd
- * Handles the map's zoomEnd event
- *
- * Parameters:
- * evt - {Object} Listener argument
- */
- zoomEnd: function(evt) {
- this.updateTimeout(evt.object, this.zoomDelay);
- },
-
- /**
- * Method: changeLayer
- * Handles the map's changeLayer event
- *
- * Parameters:
- * evt - {Object} Listener argument
- */
- changeLayer: function(evt) {
- if (evt.property === 'visibility' || evt.property === 'params') {
- this.updateTimeout(evt.object, 0);
- }
- },
-
- /**
- * Method: addLayer
- * Handles the map's addlayer event
- *
- * Parameters:
- * evt - {Object} The listener argument
- */
- addLayer: function(evt) {
- var layer = evt.layer;
- if (layer instanceof OpenLayers.Layer.Grid) {
- layer.events.on({
- addtile: this.addTile,
- retile: this.clearTileQueue,
- scope: this
- });
- var i, j, tile;
- for (i=layer.grid.length-1; i>=0; --i) {
- for (j=layer.grid[i].length-1; j>=0; --j) {
- tile = layer.grid[i][j];
- this.addTile({tile: tile});
- if (tile.url && !tile.imgDiv) {
- this.manageTileCache({object: tile});
- }
- }
- }
- }
- },
-
- /**
- * Method: removeLayer
- * Handles the map's preremovelayer event
- *
- * Parameters:
- * evt - {Object} The listener argument
- */
- removeLayer: function(evt) {
- var layer = evt.layer;
- if (layer instanceof OpenLayers.Layer.Grid) {
- this.clearTileQueue({object: layer});
- if (layer.events) {
- layer.events.un({
- addtile: this.addTile,
- retile: this.clearTileQueue,
- scope: this
- });
- }
- if (layer.grid) {
- var i, j, tile;
- for (i=layer.grid.length-1; i>=0; --i) {
- for (j=layer.grid[i].length-1; j>=0; --j) {
- tile = layer.grid[i][j];
- this.unloadTile({object: tile});
- }
- }
- }
- }
- },
-
- /**
- * Method: updateTimeout
- * Applies the <moveDelay> or <zoomDelay> to the <drawTilesFromQueue> loop,
- * and schedules more queue processing after <frameDelay> if there are still
- * tiles in the queue.
- *
- * Parameters:
- * map - {<OpenLayers.Map>} The map to update the timeout for
- * delay - {Number} The delay to apply
- * nice - {Boolean} If true, the timeout function will only be created if
- * the tilequeue is not empty. This is used by the move handler to
- * avoid impacts on dragging performance. For other events, the tile
- * queue may not be populated yet, so we need to set the timer
- * regardless of the queue size.
- */
- updateTimeout: function(map, delay, nice) {
- window.clearTimeout(this.tileQueueId[map.id]);
- var tileQueue = this.tileQueue[map.id];
- if (!nice || tileQueue.length) {
- this.tileQueueId[map.id] = window.setTimeout(
- OpenLayers.Function.bind(function() {
- this.drawTilesFromQueue(map);
- if (tileQueue.length) {
- this.updateTimeout(map, this.frameDelay);
- }
- }, this), delay
- );
- }
- },
-
- /**
- * Method: addTile
- * Listener for the layer's addtile event
- *
- * Parameters:
- * evt - {Object} The listener argument
- */
- addTile: function(evt) {
- if (evt.tile instanceof OpenLayers.Tile.Image) {
- evt.tile.events.on({
- beforedraw: this.queueTileDraw,
- beforeload: this.manageTileCache,
- loadend: this.addToCache,
- unload: this.unloadTile,
- scope: this
- });
- } else {
- // Layer has the wrong tile type, so don't handle it any longer
- this.removeLayer({layer: evt.tile.layer});
- }
- },
-
- /**
- * Method: unloadTile
- * Listener for the tile's unload event
- *
- * Parameters:
- * evt - {Object} The listener argument
- */
- unloadTile: function(evt) {
- var tile = evt.object;
- tile.events.un({
- beforedraw: this.queueTileDraw,
- beforeload: this.manageTileCache,
- loadend: this.addToCache,
- unload: this.unloadTile,
- scope: this
- });
- OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id], tile);
- },
-
- /**
- * Method: queueTileDraw
- * Adds a tile to the queue that will draw it.
- *
- * Parameters:
- * evt - {Object} Listener argument of the tile's beforedraw event
- */
- queueTileDraw: function(evt) {
- var tile = evt.object;
- var queued = false;
- var layer = tile.layer;
- var url = layer.getURL(tile.bounds);
- var img = this.tileCache[url];
- if (img && img.className !== 'olTileImage') {
- // cached image no longer valid, e.g. because we're olTileReplacing
- delete this.tileCache[url];
- OpenLayers.Util.removeItem(this.tileCacheIndex, url);
- img = null;
- }
- // queue only if image with same url not cached already
- if (layer.url && (layer.async || !img)) {
- // add to queue only if not in queue already
- var tileQueue = this.tileQueue[layer.map.id];
- if (!~OpenLayers.Util.indexOf(tileQueue, tile)) {
- tileQueue.push(tile);
- }
- queued = true;
- }
- return !queued;
- },
-
- /**
- * Method: drawTilesFromQueue
- * Draws tiles from the tileQueue, and unqueues the tiles
- */
- drawTilesFromQueue: function(map) {
- var tileQueue = this.tileQueue[map.id];
- var limit = this.tilesPerFrame;
- var animating = map.zoomTween && map.zoomTween.playing;
- while (!animating && tileQueue.length && limit) {
- tileQueue.shift().draw(true);
- --limit;
- }
- },
-
- /**
- * Method: manageTileCache
- * Adds, updates, removes and fetches cache entries.
- *
- * Parameters:
- * evt - {Object} Listener argument of the tile's beforeload event
- */
- manageTileCache: function(evt) {
- var tile = evt.object;
- var img = this.tileCache[tile.url];
- if (img) {
- // if image is on its layer's backbuffer, remove it from backbuffer
- if (img.parentNode &&
- OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer')) {
- img.parentNode.removeChild(img);
- img.id = null;
- }
- // only use image from cache if it is not on a layer already
- if (!img.parentNode) {
- img.style.visibility = 'hidden';
- img.style.opacity = 0;
- tile.setImage(img);
- // LRU - move tile to the end of the array to mark it as the most
- // recently used
- OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url);
- this.tileCacheIndex.push(tile.url);
- }
- }
- },
-
- /**
- * Method: addToCache
- *
- * Parameters:
- * evt - {Object} Listener argument for the tile's loadend event
- */
- addToCache: function(evt) {
- var tile = evt.object;
- if (!this.tileCache[tile.url]) {
- if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) {
- if (this.tileCacheIndex.length >= this.cacheSize) {
- delete this.tileCache[this.tileCacheIndex[0]];
- this.tileCacheIndex.shift();
- }
- this.tileCache[tile.url] = tile.imgDiv;
- this.tileCacheIndex.push(tile.url);
- }
- }
- },
-
- /**
- * Method: clearTileQueue
- * Clears the tile queue from tiles of a specific layer
- *
- * Parameters:
- * evt - {Object} Listener argument of the layer's retile event
- */
- clearTileQueue: function(evt) {
- var layer = evt.object;
- var tileQueue = this.tileQueue[layer.map.id];
- for (var i=tileQueue.length-1; i>=0; --i) {
- if (tileQueue[i].layer === layer) {
- tileQueue.splice(i, 1);
- }
- }
- },
-
- /**
- * Method: destroy
- */
- destroy: function() {
- for (var i=this.maps.length-1; i>=0; --i) {
- this.removeMap(this.maps[i]);
- }
- this.maps = null;
- this.tileQueue = null;
- this.tileQueueId = null;
- this.tileCache = null;
- this.tileCacheIndex = null;
- this._destroyed = true;
- }
-
-});